Initial checkin
This commit is contained in:
parent
bd02b76e5d
commit
a19589abb4
|
@ -0,0 +1,266 @@
|
||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
# Acquire lock on source tree
|
||||||
|
parent=$(ps h -o comm $PPID)
|
||||||
|
if [ "$parent" != "flock" ]; then
|
||||||
|
exec flock ".lock" $0 "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
usage()
|
||||||
|
{
|
||||||
|
prog=$(basename $0)
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Usage:"
|
||||||
|
echo " $prog [options] <build_combo>"
|
||||||
|
echo ""
|
||||||
|
echo " Options:"
|
||||||
|
echo " -a Automated build (check for clean working dir)"
|
||||||
|
echo " -c Clean output before build"
|
||||||
|
echo " Given once, clean device output (out/target/product)"
|
||||||
|
echo " Given twice, clean target output (out/target)"
|
||||||
|
echo " Given thrice, clean all output (out)"
|
||||||
|
echo " -C Clean output after successful build"
|
||||||
|
echo " Given once, clean device output (out/target/product)"
|
||||||
|
echo " Given twice, clean target output (out/target)"
|
||||||
|
echo " Given thrice, clean all output (out)"
|
||||||
|
echo " -j Specify -j value for make [CPUS]"
|
||||||
|
echo " -l Save build output to log file"
|
||||||
|
echo " -o Specify output directory"
|
||||||
|
echo " -O Specify Android out dir"
|
||||||
|
echo " -s Show commands"
|
||||||
|
echo " -t Specify make target [auto]"
|
||||||
|
echo " -v Specify version [none]"
|
||||||
|
echo ""
|
||||||
|
echo "Exit status: 0 on success, !0 on failure"
|
||||||
|
echo ""
|
||||||
|
echo "On success, output will be copied to \$TARGET_PRODUCT.zip."
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Tool locations
|
||||||
|
# XXX: not darwin compatible
|
||||||
|
CCACHE="prebuilts/misc/linux-x86/ccache/ccache"
|
||||||
|
|
||||||
|
ccache_stats()
|
||||||
|
{
|
||||||
|
# Calculate ccache stats
|
||||||
|
local ch=0
|
||||||
|
local cm=0
|
||||||
|
local ct=0
|
||||||
|
local cpct="NA"
|
||||||
|
|
||||||
|
OLDIFS="$IFS"
|
||||||
|
IFS=$'\n'
|
||||||
|
lines=($($CCACHE -s))
|
||||||
|
IFS="$OLDIFS"
|
||||||
|
for (( n=0; $n < ${#lines[*]}; n=$(($n+1)) )); do
|
||||||
|
line=${lines[$n]}
|
||||||
|
if [ "${line:0:9}" = "cache hit" ]; then
|
||||||
|
ch=$(( ch + $(echo $line | sed 's/[^0-9]*//') ))
|
||||||
|
elif [ "${line:0:10}" = "cache miss" ]; then
|
||||||
|
read -a fields <<<$line
|
||||||
|
cm=$(( cm + $(echo $line | sed 's/[^0-9]*//') ))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
IFS="$OLDIFS"
|
||||||
|
if [ -n "$ch" -a -n "$cm" ]; then
|
||||||
|
ct=$(($ch+$cm))
|
||||||
|
fi
|
||||||
|
if [ "$ct" -gt 0 ]; then
|
||||||
|
cpct=$((ch*100/ct))
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "ch=$ch"
|
||||||
|
echo "cm=$cm"
|
||||||
|
echo "ct=$ct"
|
||||||
|
echo "cpct=$cpct"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set some useful vars
|
||||||
|
export USE_CCACHE=1
|
||||||
|
export CPUS=$(grep "^processor" /proc/cpuinfo | wc -l)
|
||||||
|
export MEM=$(cat /proc/meminfo | grep "^MemTotal" | grep -o "[0-9]*")
|
||||||
|
|
||||||
|
# Find actual value for jobs.
|
||||||
|
# - No more than 8 jobs
|
||||||
|
# - No more than one job per cpu
|
||||||
|
# - No more than one job per 1.5gb
|
||||||
|
max_jobs=8
|
||||||
|
cpu_jobs="$CPUS"
|
||||||
|
if [ "$cpu_jobs" -lt "$max_jobs" ]; then
|
||||||
|
max_jobs="$cpu_jobs"
|
||||||
|
fi
|
||||||
|
mem_jobs=$(($MEM/1572864))
|
||||||
|
if [ "$mem_jobs" -lt "$max_jobs" ]; then
|
||||||
|
max_jobs="$mem_jobs"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Init options
|
||||||
|
opt_automated=0
|
||||||
|
opt_clean=0
|
||||||
|
opt_postclean=0
|
||||||
|
opt_jobs="$max_jobs"
|
||||||
|
opt_log=0
|
||||||
|
opt_outdir="."
|
||||||
|
opt_outandroid=""
|
||||||
|
opt_maketarget="auto"
|
||||||
|
opt_showcommands=0
|
||||||
|
opt_version=""
|
||||||
|
while getopts "acCj:lo:O:st:v:" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
a) opt_automated=1 ;;
|
||||||
|
c) opt_clean=$(($opt_clean+1)) ;;
|
||||||
|
C) opt_postclean=$(($opt_postclean+1)) ;;
|
||||||
|
j) opt_jobs="$OPTARG" ;;
|
||||||
|
l) opt_log=1 ;;
|
||||||
|
o) opt_outdir="$OPTARG" ;;
|
||||||
|
O) opt_outandroid="$OPTARG" ;;
|
||||||
|
s) opt_showcommands=1 ;;
|
||||||
|
t) opt_maketarget="$OPTARG" ;;
|
||||||
|
v) opt_version="$OPTARG" ;;
|
||||||
|
*) usage
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $(($OPTIND-1))
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$opt_outandroid" ]; then
|
||||||
|
export OUT_DIR_COMMON_BASE="$opt_outandroid"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$opt_outdir"
|
||||||
|
|
||||||
|
# NB: "$combo" is used by build scripts
|
||||||
|
build_combo="$1"
|
||||||
|
project_device=$(echo $build_combo | cut -d'-' -f1)
|
||||||
|
project=$(echo $project_device | cut -d'_' -f1)
|
||||||
|
device=$(echo $project_device | cut -d'_' -f2)
|
||||||
|
|
||||||
|
# Desired output files
|
||||||
|
if [ -n "$opt_version" ]; then
|
||||||
|
out_name="${opt_outdir}/${project_device}-${opt_version}"
|
||||||
|
else
|
||||||
|
out_name="${opt_outdir}/${project_device}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$opt_log" -ne 0 ]; then
|
||||||
|
rm -f "${out_name}.log"
|
||||||
|
exec >> "${out_name}.log" 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d ".repo" ]; then
|
||||||
|
echo "Invalid build tree"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$opt_clean" in
|
||||||
|
0) # Do nothing
|
||||||
|
;;
|
||||||
|
1) # Clean device output
|
||||||
|
rm -rf "$OUT_DIR_COMMON_BASE/target/product"
|
||||||
|
;;
|
||||||
|
2) # Clean target output
|
||||||
|
rm -rf "$OUT_DIR_COMMON_BASE/target"
|
||||||
|
;;
|
||||||
|
*) # Clean all output
|
||||||
|
rm -rf "$OUT_DIR_COMMON_BASE"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Detect make target
|
||||||
|
if [ -z "$opt_maketarget" -o "$opt_maketarget" = "auto" ]; then
|
||||||
|
opt_maketarget="otapackage"
|
||||||
|
if [ -f "build/core/Makefile" ]; then
|
||||||
|
if grep -q "^bacon:" "build/core/Makefile"; then
|
||||||
|
opt_maketarget="bacon"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$opt_showcommands" -ne 0 ]; then
|
||||||
|
opt_maketarget="showcommands $opt_maketarget"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure working directory is clean
|
||||||
|
if [ "$opt_automated" -ne 0 ]; then
|
||||||
|
android-repo status | grep -q "working directory clean"
|
||||||
|
fi
|
||||||
|
|
||||||
|
. build/envsetup.sh
|
||||||
|
lunch "$build_combo"
|
||||||
|
|
||||||
|
# Setup ccache
|
||||||
|
if [ -z "$CCACHE_ROOT" ]; then
|
||||||
|
CCACHE_ROOT="$HOME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export CCACHE_DIR="$CCACHE_ROOT/.ccache-$project_device"
|
||||||
|
if [ ! -d "$CCACHE_DIR" ]; then
|
||||||
|
mkdir -p "$CCACHE_DIR"
|
||||||
|
$CCACHE -M 8G
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean some things
|
||||||
|
rm -f $OUT/system/build.prop
|
||||||
|
|
||||||
|
eval $(ccache_stats)
|
||||||
|
sch=$ch
|
||||||
|
scm=$cm
|
||||||
|
sct=$ct
|
||||||
|
scpct=$cpct
|
||||||
|
|
||||||
|
# Do the build
|
||||||
|
stime=$(date +%s)
|
||||||
|
make -j${opt_jobs} ${opt_maketarget}
|
||||||
|
etime=$(date +%s)
|
||||||
|
|
||||||
|
# Find output zip
|
||||||
|
built_zip=$(ls -t $OUT/*.zip | head -1)
|
||||||
|
if [ ! -f "$built_zip" ]; then
|
||||||
|
echo "Error: cannot find built zip in $OUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy output zip to well known place
|
||||||
|
cp "$built_zip" "${out_name}.zip"
|
||||||
|
|
||||||
|
# Calculate elapsed time
|
||||||
|
elapsedsec=$((etime - stime))
|
||||||
|
elapsed=$(printf "%02d:%02d" $((elapsedsec/60)) $((elapsedsec%60)))
|
||||||
|
|
||||||
|
eval $(ccache_stats)
|
||||||
|
ech=$ch
|
||||||
|
ecm=$cm
|
||||||
|
ect=$ct
|
||||||
|
ecpct=$cpct
|
||||||
|
|
||||||
|
dch=$((ech - sch))
|
||||||
|
dcm=$((ecm - scm))
|
||||||
|
dct=$((ect - sct))
|
||||||
|
dcpct="NA"
|
||||||
|
if [ "$dct" -gt 0 ]; then
|
||||||
|
dcpct=$((dch*100/dct))
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Build complete."
|
||||||
|
echo "elapsed time : $elapsed"
|
||||||
|
echo "ccache totals: $ech/$ect ($ecpct%)"
|
||||||
|
echo "ccache deltas: $dch/$dct ($dcpct%)"
|
||||||
|
|
||||||
|
case "$opt_postclean" in
|
||||||
|
0) # Do nothing
|
||||||
|
;;
|
||||||
|
1) # Clean device output
|
||||||
|
rm -rf "$OUT_DIR_COMMON_BASE/target/product"
|
||||||
|
;;
|
||||||
|
2) # Clean target output
|
||||||
|
rm -rf "$OUT_DIR_COMMON_BASE/target"
|
||||||
|
;;
|
||||||
|
*) # Clean all output
|
||||||
|
rm -rf "$OUT_DIR_COMMON_BASE"
|
||||||
|
;;
|
||||||
|
esac
|
|
@ -0,0 +1,264 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import getopt
|
||||||
|
import subprocess
|
||||||
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
|
def read_manifest(file):
|
||||||
|
manifest = ElementTree.parse(file)
|
||||||
|
defaults = manifest.findall('default')[0]
|
||||||
|
for project in manifest.findall('project'):
|
||||||
|
if not 'remote' in project.attrib:
|
||||||
|
project.attrib['remote'] = defaults.attrib['remote']
|
||||||
|
if not 'revision' in project.attrib:
|
||||||
|
project.attrib['revision'] = defaults.attrib['revision']
|
||||||
|
return manifest
|
||||||
|
|
||||||
|
def manifest_defaults(manifest):
|
||||||
|
defaults = dict()
|
||||||
|
|
||||||
|
defaults['remote'] = ''
|
||||||
|
defaults['revision'] = ''
|
||||||
|
for e in manifest.findall('default'):
|
||||||
|
if 'remote' in e:
|
||||||
|
defaults['remote'] = e.attrib['remote']
|
||||||
|
if 'revision' in e:
|
||||||
|
defaults['revision'] = e.attrib['revision']
|
||||||
|
|
||||||
|
oldpwd = os.getcwd()
|
||||||
|
os.chdir('.repo/manifests')
|
||||||
|
pipe = subprocess.Popen(['git', 'remote', '-v'], stdout=subprocess.PIPE)
|
||||||
|
line = pipe.stdout.readline()
|
||||||
|
fields = line.split()
|
||||||
|
defaults['fetch'] = os.path.dirname(fields[1])
|
||||||
|
os.chdir(oldpwd)
|
||||||
|
|
||||||
|
return defaults
|
||||||
|
|
||||||
|
def manifest_remotes(manifest, defaults):
|
||||||
|
remotes = dict()
|
||||||
|
for e in manifest.findall('remote'):
|
||||||
|
if not 'name' in e.attrib:
|
||||||
|
print "ERROR: remote with no name attrib"
|
||||||
|
continue
|
||||||
|
name = e.attrib['name']
|
||||||
|
if not 'fetch' in e.attrib:
|
||||||
|
print "ERROR: remote with no fetch attrib"
|
||||||
|
continue
|
||||||
|
e.attrib['fetch'] = e.attrib['fetch'].rstrip('/')
|
||||||
|
if e.attrib['fetch'] == '.':
|
||||||
|
e.attrib['fetch'] = defaults['fetch']
|
||||||
|
if e.attrib['fetch'] == '..':
|
||||||
|
e.attrib['fetch'] = os.path.dirname(defaults['fetch'])
|
||||||
|
remotes[name] = e
|
||||||
|
return remotes
|
||||||
|
|
||||||
|
def manifest_projects(manifest, remotes, defaults):
|
||||||
|
projects = dict()
|
||||||
|
for e in manifest.findall('project'):
|
||||||
|
if not 'name' in e.attrib:
|
||||||
|
print "ERROR: project with no name attrib"
|
||||||
|
continue
|
||||||
|
if not 'path' in e.attrib:
|
||||||
|
e.attrib['path'] = e.attrib['name']
|
||||||
|
path = e.attrib['path']
|
||||||
|
if path in projects:
|
||||||
|
print "ERROR: duplicate project path %s" % path
|
||||||
|
continue
|
||||||
|
if not 'remote' in e.attrib:
|
||||||
|
e.attrib['remote'] = defaults['remote']
|
||||||
|
remote_name = e.attrib['remote']
|
||||||
|
r = remotes[remote_name]
|
||||||
|
e.attrib['remote_url'] = r.attrib['fetch'] + '/' + e.attrib['name']
|
||||||
|
projects[path] = e
|
||||||
|
return projects
|
||||||
|
|
||||||
|
def is_same_project(p1, p2):
|
||||||
|
if p1.attrib['path'] != p2.attrib['path']:
|
||||||
|
return False
|
||||||
|
if p1.attrib['remote_url'] != p2.attrib['remote_url']:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def run_git_in_dir(path, args):
|
||||||
|
pipe = os.popen("chdir %s && git %s" % (path, args))
|
||||||
|
lines = pipe.readlines()
|
||||||
|
pipe.close()
|
||||||
|
return lines
|
||||||
|
|
||||||
|
class TextEmitter:
|
||||||
|
def emit_header(self, f1, f2):
|
||||||
|
print "# Changelog"
|
||||||
|
print "# Created ..."
|
||||||
|
print "# %s vs %s" % (f1, f2)
|
||||||
|
|
||||||
|
def emit_footer(self):
|
||||||
|
# empty
|
||||||
|
pass
|
||||||
|
|
||||||
|
def emit_project_change_header(self):
|
||||||
|
print "=" * 72
|
||||||
|
print "Project changes ..."
|
||||||
|
|
||||||
|
def emit_project_change_text(self, text):
|
||||||
|
print "%s" % text
|
||||||
|
|
||||||
|
def emit_project_change_footer(self):
|
||||||
|
print ""
|
||||||
|
|
||||||
|
def emit_dir_changes_header(self, name, r1, r2):
|
||||||
|
print "=" * 72
|
||||||
|
print "Changes in %s [%s .. %s]" % (name, r1, r2)
|
||||||
|
print "=" * 72
|
||||||
|
print ""
|
||||||
|
|
||||||
|
def emit_dir_changes_text(self, remote_url, text):
|
||||||
|
for line in text:
|
||||||
|
print line.rstrip()
|
||||||
|
|
||||||
|
def emit_dir_changes_footer(self):
|
||||||
|
print ""
|
||||||
|
|
||||||
|
class HtmlEmitter:
|
||||||
|
def emit_header(self, f1, f2):
|
||||||
|
print "<html>"
|
||||||
|
print " <head>"
|
||||||
|
print " <title>Changelog</title>"
|
||||||
|
print " </head>"
|
||||||
|
print " <body>"
|
||||||
|
|
||||||
|
def emit_footer(self):
|
||||||
|
print " </body>"
|
||||||
|
print "</html>"
|
||||||
|
|
||||||
|
def emit_project_change_header(self):
|
||||||
|
print " <h3>Project changes</h3>"
|
||||||
|
print " <hr>"
|
||||||
|
|
||||||
|
def emit_project_change_text(self, text):
|
||||||
|
print " %s<br>" % text
|
||||||
|
|
||||||
|
def emit_project_change_footer(self):
|
||||||
|
# empty
|
||||||
|
pass
|
||||||
|
|
||||||
|
def emit_dir_changes_header(self, name, r1, r2):
|
||||||
|
print " <h3>Changes in %s [%s .. %s]</h3>" % (name, r1, r2)
|
||||||
|
print " <hr>"
|
||||||
|
|
||||||
|
def emit_dir_changes_text(self, remote_url, text):
|
||||||
|
print " <pre>"
|
||||||
|
for line in text:
|
||||||
|
txt = line.rstrip()
|
||||||
|
if line[0:7] == 'commit ' and remote_url.find('github.com') != -1:
|
||||||
|
id = line[7:]
|
||||||
|
lnk = '%s/commit/%s' % (remote_url, id)
|
||||||
|
txt = '<a href="%s">%s</a>' % (lnk, id)
|
||||||
|
print " %s" % txt
|
||||||
|
print " </pre>"
|
||||||
|
|
||||||
|
def emit_dir_changes_footer(self):
|
||||||
|
# empty
|
||||||
|
pass
|
||||||
|
|
||||||
|
fmt = 'text'
|
||||||
|
showmerges = False
|
||||||
|
short = False
|
||||||
|
|
||||||
|
opts, args = getopt.getopt(sys.argv[1:], 'f:ms', ['format=', 'show-merges', 'short'])
|
||||||
|
for k, v in opts:
|
||||||
|
if k in ('-f', '--format'):
|
||||||
|
fmt = v
|
||||||
|
if k in ('-m', '--show-merges'):
|
||||||
|
showmerges = True
|
||||||
|
if k in ('-s', '--short'):
|
||||||
|
short = True
|
||||||
|
|
||||||
|
if len(args) != 2:
|
||||||
|
print "Usage: %s [-f text|html] [-m] manifest1 manifest2"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
f1 = args[0]
|
||||||
|
f2 = args[1]
|
||||||
|
manifest1 = read_manifest(f1)
|
||||||
|
manifest2 = read_manifest(f2)
|
||||||
|
defaults1 = manifest_defaults(manifest1)
|
||||||
|
defaults2 = manifest_defaults(manifest2)
|
||||||
|
remotes1 = manifest_remotes(manifest1, defaults1)
|
||||||
|
remotes2 = manifest_remotes(manifest2, defaults2)
|
||||||
|
projects1 = manifest_projects(manifest1, remotes1, defaults1)
|
||||||
|
projects2 = manifest_projects(manifest2, remotes2, defaults2)
|
||||||
|
|
||||||
|
diffable_projects = []
|
||||||
|
changed_projects = []
|
||||||
|
new_projects = []
|
||||||
|
del_projects = []
|
||||||
|
|
||||||
|
for path in projects1.iterkeys():
|
||||||
|
if path in projects2:
|
||||||
|
p1 = projects1[path]
|
||||||
|
p2 = projects2[path]
|
||||||
|
if is_same_project(p1, p2):
|
||||||
|
diffable_projects.append(path)
|
||||||
|
else:
|
||||||
|
changed_projects.append(path)
|
||||||
|
else:
|
||||||
|
del_projects.append(path)
|
||||||
|
|
||||||
|
for path in projects2.iterkeys():
|
||||||
|
if not path in projects1:
|
||||||
|
new_projects.append(path)
|
||||||
|
|
||||||
|
if fmt == 'text':
|
||||||
|
emitter = TextEmitter()
|
||||||
|
else:
|
||||||
|
emitter = HtmlEmitter()
|
||||||
|
|
||||||
|
emitter.emit_header(f1, f2)
|
||||||
|
|
||||||
|
if len(new_projects) > 0 or len(del_projects) > 0 or len(changed_projects) > 0:
|
||||||
|
emitter.emit_project_change_header()
|
||||||
|
|
||||||
|
for path in new_projects:
|
||||||
|
remote_url = projects2[path].attrib['remote_url']
|
||||||
|
emitter.emit_project_change_text("new project %s: %s" % (path, remote_url))
|
||||||
|
|
||||||
|
for path in del_projects:
|
||||||
|
remote_url = projects1[path].attrib['remote_url']
|
||||||
|
emitter.emit_project_change_text("deleted project %s: %s" % (path, remote_url))
|
||||||
|
|
||||||
|
for path in changed_projects:
|
||||||
|
old_remote_url = projects1[path].attrib['remote_url']
|
||||||
|
new_remote_url = projects2[path].attrib['remote_url']
|
||||||
|
emitter.emit_project_change_text("changed project %s: %s => %s" % (path, old_remote_url, new_remote_url))
|
||||||
|
|
||||||
|
emitter.emit_project_change_footer()
|
||||||
|
|
||||||
|
for path in sorted(diffable_projects):
|
||||||
|
p1 = projects1[path]
|
||||||
|
r1 = p1.attrib['revision']
|
||||||
|
p2 = projects2[path]
|
||||||
|
r2 = p2.attrib['revision']
|
||||||
|
if r1 != r2:
|
||||||
|
lines = run_git_in_dir(path, "show --pretty=format:%%h %s" % (r1))
|
||||||
|
r1a = lines[0].rstrip('\n')
|
||||||
|
lines = run_git_in_dir(path, "show --pretty=format:%%h %s" % (r2))
|
||||||
|
r2a = lines[0].rstrip('\n')
|
||||||
|
gitargs = "log "
|
||||||
|
if not showmerges:
|
||||||
|
gitargs += "--no-merges "
|
||||||
|
if short:
|
||||||
|
gitargs += "--pretty=oneline "
|
||||||
|
else:
|
||||||
|
gitargs += "--pretty=short "
|
||||||
|
gitargs += "--abbrev-commit "
|
||||||
|
gitargs += "%s..%s" % (p1.attrib['revision'], p2.attrib['revision'])
|
||||||
|
lines = run_git_in_dir(path, gitargs)
|
||||||
|
if len(lines) > 0:
|
||||||
|
emitter.emit_dir_changes_header(path, r1a, r2a)
|
||||||
|
emitter.emit_dir_changes_text(p1.attrib['remote_url'], lines)
|
||||||
|
emitter.emit_dir_changes_footer()
|
||||||
|
|
||||||
|
emitter.emit_footer()
|
|
@ -0,0 +1,45 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
topdir=$(pwd)
|
||||||
|
|
||||||
|
if [ "$#" -ne 1 ]; then
|
||||||
|
echo "Usage: $0 <create|restore>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
action="$1"
|
||||||
|
|
||||||
|
create_tag()
|
||||||
|
{
|
||||||
|
# XXX: should verify "git status" to ensure to uncommitted diffs
|
||||||
|
repo manifest -r | cat
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_tag()
|
||||||
|
{
|
||||||
|
while read line; do
|
||||||
|
prj_entry=$(echo $line | grep "<project ")
|
||||||
|
if [ -z "$prj_entry" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
dir=$(echo $prj_entry | egrep -o "path=([^ ]*)" | cut -d'"' -f2)
|
||||||
|
tag=$(echo $prj_entry | egrep -o "revision=([^ ]*)" | cut -d'"' -f2)
|
||||||
|
if [ -z "$dir" -o -z "$tag" ]; then
|
||||||
|
echo "Malformed line $line"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ ! -d "$topdir/$dir" ]; then
|
||||||
|
echo "No such dir $dir"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo "$dir -> $tag"
|
||||||
|
cd "$topdir/$dir"
|
||||||
|
git checkout "$tag"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$action" in
|
||||||
|
create) create_tag ;;
|
||||||
|
restore) restore_tag ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
|
@ -0,0 +1,240 @@
|
||||||
|
#!/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['nodo'] = False
|
||||||
|
cfg['post'] = None
|
||||||
|
cfg['remote'] = None
|
||||||
|
cfg['revision'] = None
|
||||||
|
cfg['ssh'] = False
|
||||||
|
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
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print "Usage: gerrit-fetch [args] <change-num>"
|
||||||
|
print " --nodo Do not apply the change"
|
||||||
|
print " --post Apply change after fetching (cherry-pick|merge)"
|
||||||
|
print " --remote Use specified remote"
|
||||||
|
print " --revision Use specified change revision"
|
||||||
|
print " --ssh Use ssh, do not attempt http"
|
||||||
|
print " --verbose Increase verbose level"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
optargs, argv = getopt.getopt(sys.argv[1:], 'np:sv',
|
||||||
|
['nodo', 'post=', 'remote=', 'revision=', 'ssh', 'verbose'])
|
||||||
|
for k, v in optargs:
|
||||||
|
if k in ('-n', '--nodo'):
|
||||||
|
cfg['nodo'] = True
|
||||||
|
if k in ('-p', '--post'):
|
||||||
|
cfg['post'] = v
|
||||||
|
if k in ('--remote'):
|
||||||
|
cfg['remote'] = v
|
||||||
|
if k in ('--revision'):
|
||||||
|
cfg['revision'] = v
|
||||||
|
if k in ('-s', '--ssh'):
|
||||||
|
cfg['ssh'] = True
|
||||||
|
if k in ('-v', '--verbose'):
|
||||||
|
cfg['verbose'] += 1
|
||||||
|
|
||||||
|
if not cfg['post'] is None:
|
||||||
|
if cfg['post'] != 'cherry-pick' and cfg['post'] != 'merge':
|
||||||
|
usage()
|
||||||
|
|
||||||
|
if len(argv) != 1:
|
||||||
|
usage()
|
||||||
|
|
||||||
|
change_number = int(argv[0])
|
||||||
|
|
||||||
|
cur_dir = os.getcwd()
|
||||||
|
print "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)
|
||||||
|
print "top_dir=%s" % (top_dir)
|
||||||
|
if len(top_dir) < len(cur_dir):
|
||||||
|
prj_dir = cur_dir[len(top_dir)+1:]
|
||||||
|
print "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 prj_dir is None:
|
||||||
|
for elem in manifest.findall('default'):
|
||||||
|
cfg['remote'] = elem.get('name')
|
||||||
|
else:
|
||||||
|
for elem in manifest.findall('project'):
|
||||||
|
if elem.get('path') == prj_dir:
|
||||||
|
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 = "http://%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))
|
||||||
|
|
||||||
|
# Fetch the change props
|
||||||
|
props = None
|
||||||
|
project_name = None
|
||||||
|
change_revision = cfg['revision']
|
||||||
|
if not cfg['ssh']:
|
||||||
|
try:
|
||||||
|
# NB: o=DOWNLOAD_COMMANDS is not reliable so don't use it
|
||||||
|
url = '%s/changes/?q=%d&o=CURRENT_REVISION' % (review_url, change_number)
|
||||||
|
verbose("Attempting to fetch change from url=%s\n" % (url))
|
||||||
|
response = urllib2.urlopen(url)
|
||||||
|
doc = response.read()
|
||||||
|
if not doc.startswith(")]}'\n"):
|
||||||
|
sys.stderr.write('Error: malformed change props (url=%s)\n' % (url))
|
||||||
|
raise Exception('Malformed change props')
|
||||||
|
proplist = json.loads(doc[5:])
|
||||||
|
if len(proplist) == 1:
|
||||||
|
verbose("proplist loads and has one element\n");
|
||||||
|
props = proplist[0]
|
||||||
|
project_name = props['project']
|
||||||
|
if change_revision is None:
|
||||||
|
change_rev_id = props['current_revision']
|
||||||
|
change_rev = None
|
||||||
|
for rev in props['revisions']:
|
||||||
|
if rev == change_rev_id:
|
||||||
|
change_revision = props['revisions'][rev]['_number']
|
||||||
|
except:
|
||||||
|
sys.stderr.write('Failed to fetch change props\n')
|
||||||
|
|
||||||
|
if project_name is None:
|
||||||
|
args = []
|
||||||
|
args.append('ssh')
|
||||||
|
args.append(review_host)
|
||||||
|
args.append('gerrit')
|
||||||
|
args.append('query')
|
||||||
|
args.append('--format=JSON')
|
||||||
|
args.append('--current-patch-set')
|
||||||
|
args.append("%d" %(change_number))
|
||||||
|
verbose("Attempting to fetch change from cmd=\"%s\"\n" % (" ".join(args)))
|
||||||
|
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)
|
||||||
|
lines = out.split('\n')
|
||||||
|
props = json.loads(lines[0])
|
||||||
|
project_name = props['project']
|
||||||
|
if change_revision is None:
|
||||||
|
change_revision = props['currentPatchSet']['number']
|
||||||
|
|
||||||
|
# If we used ssh to access the change, also use ssh to fetch it
|
||||||
|
review_url = "ssh://%s" % (review_host)
|
||||||
|
|
||||||
|
if project_name is None:
|
||||||
|
sys.stderr.write('Error: cannot fetch change properties\n')
|
||||||
|
sys.exit(1)
|
||||||
|
verbose("project=%s\n" % (project_name))
|
||||||
|
|
||||||
|
if change_revision is None:
|
||||||
|
sys.stderr.write('Error: cannot fetch change revision\n')
|
||||||
|
sys.exit(1)
|
||||||
|
verbose("change_revision=%s\n" % (change_revision))
|
||||||
|
|
||||||
|
project = None
|
||||||
|
for elem in manifest.findall('project'):
|
||||||
|
if elem.get('name') == project_name:
|
||||||
|
project = elem
|
||||||
|
if project is None:
|
||||||
|
sys.stderr.write('Error: project not found\n')
|
||||||
|
sys.exit(1)
|
||||||
|
project_path = project.get('path')
|
||||||
|
|
||||||
|
if prj_dir is None:
|
||||||
|
# Switch to the project directory
|
||||||
|
verbose("Switching to project directory %s\n" % (project_path))
|
||||||
|
try:
|
||||||
|
os.chdir(project_path)
|
||||||
|
except:
|
||||||
|
sys.stderr.write('Error: path not found\n')
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
# Verify correct directory
|
||||||
|
verbose("Verifying project directory %s vs %s\n" % (project_path, prj_dir))
|
||||||
|
if prj_dir != project_path:
|
||||||
|
sys.stderr.write("Error: change applies to %s, we are in %s\n" % (project_path, prj_dir))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
change_hash = "%02d" % (change_number % 100)
|
||||||
|
|
||||||
|
# Fetch the change
|
||||||
|
args = []
|
||||||
|
args.append('git')
|
||||||
|
args.append('fetch')
|
||||||
|
args.append('%s/%s' % (review_url, project_name))
|
||||||
|
args.append('refs/changes/%s/%s/%s' % (change_hash, change_number, change_revision))
|
||||||
|
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 fetch change\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not cfg['post'] is None:
|
||||||
|
# Pick the change
|
||||||
|
args = []
|
||||||
|
args.append('git')
|
||||||
|
args.append(cfg['post'])
|
||||||
|
args.append('FETCH_HEAD')
|
||||||
|
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 %s change\n" % (cfg['post']))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
verbose('Success\n')
|
||||||
|
sys.exit(0)
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
exec gerrit-fetch --post=cherry-pick "$@"
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
exec gerrit-fetch --post=pull "$@"
|
|
@ -0,0 +1,54 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
find_topdir()
|
||||||
|
{
|
||||||
|
while [ ! -d ".repo" ]; do
|
||||||
|
cd ".."
|
||||||
|
if [ $PWD = "/" ]; then
|
||||||
|
echo "Cannot find topdir"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
pwd
|
||||||
|
}
|
||||||
|
|
||||||
|
SCHEME="ssh"
|
||||||
|
GIT="git"
|
||||||
|
if [ "$1" = "-t" ]; then
|
||||||
|
GIT="echo git"
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
if [ "$1" = "-h" ]; then
|
||||||
|
SCHEME="https"
|
||||||
|
fi
|
||||||
|
|
||||||
|
topdir=$(find_topdir)
|
||||||
|
len=$(( ${#topdir} + 1 ))
|
||||||
|
prj_path=${PWD:$len}
|
||||||
|
|
||||||
|
prj_entry=$(repo manifest | grep "project .*path=\"$prj_path\"")
|
||||||
|
if [ -z "$prj_entry" ]; then
|
||||||
|
echo "Cannot find project entry for $prj_path"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
def_entry=$(repo manifest | grep "default ")
|
||||||
|
def_remote_name=$(echo $def_entry | egrep -o "remote=([^ ]*)" | cut -d'"' -f2)
|
||||||
|
def_remote_entry=$(repo manifest | grep "remote .*name=\"$def_remote_name\"")
|
||||||
|
|
||||||
|
prj_name=$(echo $prj_entry | egrep -o "name=([^ ]*)" | cut -d'"' -f2)
|
||||||
|
prj_remote_name=$(echo $prj_entry | egrep -o "remote=([^ ]*)" | cut -d'"' -f2)
|
||||||
|
prj_revision=$(echo $prj_entry | egrep -o "revision=([^ ]*)" | cut -d'"' -f2)
|
||||||
|
if [ -z "$prj_revision" ]; then
|
||||||
|
prj_revision=$(echo $def_entry | egrep -o "revision=([^ ]*)" | cut -d'"' -f2)
|
||||||
|
fi
|
||||||
|
prj_revision="${prj_revision##refs/heads/}"
|
||||||
|
|
||||||
|
if [ -n "$prj_remote_name" ]; then
|
||||||
|
remote_entry=$(repo manifest | grep "remote .*name=\"$prj_remote_name\"")
|
||||||
|
else
|
||||||
|
remote_entry=$(repo manifest | grep "remote .*name=\"$def_remote_name\"")
|
||||||
|
fi
|
||||||
|
remote_review=$(echo $remote_entry | egrep -o "review=([^ ]*)" | cut -d'"' -f2)
|
||||||
|
|
||||||
|
$GIT push "$SCHEME://$remote_review:29418/$prj_name" "HEAD:refs/for/$prj_revision"
|
Loading…
Reference in New Issue