summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/Makefile2
-rw-r--r--core/combo/HOST_windows-x86.mk12
-rw-r--r--core/config.mk2
-rw-r--r--core/envsetup.mk4
-rw-r--r--core/tasks/kernel.mk2
-rw-r--r--envsetup.sh6
-rwxr-xr-xtools/repopick.py250
7 files changed, 270 insertions, 8 deletions
diff --git a/core/Makefile b/core/Makefile
index 94b5561..cae5d1f 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1660,7 +1660,7 @@ $(INTERNAL_SDK_TARGET): $(deps)
MAIN_SDK_NAME := $(sdk_name)
MAIN_SDK_DIR := $(sdk_dir)
MAIN_SDK_ZIP := $(INTERNAL_SDK_TARGET)
-ifneq ($(filter win_sdk,$(MAKECMDGOALS)),)
+ifneq ($(filter win_sdk winsdk-coretools,$(MAKECMDGOALS)),)
include $(TOPDIR)development/build/tools/windows_sdk.mk
endif
diff --git a/core/combo/HOST_windows-x86.mk b/core/combo/HOST_windows-x86.mk
index 85bc1e0..bca6e31 100644
--- a/core/combo/HOST_windows-x86.mk
+++ b/core/combo/HOST_windows-x86.mk
@@ -23,22 +23,30 @@ TOOLS_PREFIX := #prebuilt/windows/host/bin/
TOOLS_EXE_SUFFIX := .exe
# Settings to use MinGW has a cross-compiler under Linux
-ifneq ($(findstring Linux,$(UNAME)),)
ifneq ($(strip $(USE_MINGW)),)
HOST_ACP_UNAVAILABLE := true
TOOLS_EXE_SUFFIX :=
HOST_GLOBAL_CFLAGS += -DUSE_MINGW
ifneq ($(strip $(BUILD_HOST_64bit)),)
+ifeq ($(BUILD_OS),darwin)
+$(error Windows amd64 cross compile builds not supported from Darwin)
+else
TOOLS_PREFIX := /usr/bin/amd64-mingw32msvc-
HOST_C_INCLUDES += /usr/lib/gcc/amd64-mingw32msvc/4.4.2/include
HOST_GLOBAL_LD_DIRS += -L/usr/amd64-mingw32msvc/lib
+endif
+else
+ifeq ($(BUILD_OS),darwin)
+TOOLS_PREFIX := /usr/local/gcc-4.8.0-qt-4.8.4-for-mingw32/win32-gcc/bin//i586-mingw32-
+HOST_C_INCLUDES += /usr/local/gcc-4.8.0-qt-4.8.4-for-mingw32/win32-gcc/i586-mingw32/include /usr/local/gcc-4.8.0-qt-4.8.4-for-mingw32/win32-gcc/i586-mingw32/include/ddk
+HOST_GLOBAL_LD_DIRS += -L/usr/local/gcc-4.8.0-qt-4.8.4-for-mingw32/win32-gcc/i586-mingw32/lib
else
TOOLS_PREFIX := /usr/bin/i586-mingw32msvc-
HOST_C_INCLUDES += /usr/lib/gcc/i586-mingw32msvc/3.4.4/include
HOST_GLOBAL_LD_DIRS += -L/usr/i586-mingw32msvc/lib
+endif
endif # BUILD_HOST_64bit
endif # USE_MINGW
-endif # Linux
HOST_CC := $(TOOLS_PREFIX)gcc$(TOOLS_EXE_SUFFIX)
HOST_CXX := $(TOOLS_PREFIX)g++$(TOOLS_EXE_SUFFIX)
diff --git a/core/config.mk b/core/config.mk
index ab06f6a..90237b7 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -336,7 +336,7 @@ endif
OLD_FLEX := prebuilts/misc/$(HOST_PREBUILT_TAG)/flex/flex-2.5.4a$(HOST_EXECUTABLE_SUFFIX)
-ifeq ($(HOST_OS),darwin)
+ifeq ($(BUILD_OS),darwin)
# Mac OS' screwy version of java uses a non-standard directory layout
# and doesn't even seem to have tools.jar. On the other hand, javac seems
# to be able to magically find the classes in there, wherever they are, so
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 7a3ec92..1211887 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -55,13 +55,11 @@ endif
# BUILD_OS is the real host doing the build.
BUILD_OS := $(HOST_OS)
-# Under Linux, if USE_MINGW is set, we change HOST_OS to Windows to build the
+# If USE_MINGW is set, we change HOST_OS to Windows to build the
# Windows SDK. Only a subset of tools and SDK will manage to build properly.
-ifeq ($(HOST_OS),linux)
ifneq ($(USE_MINGW),)
HOST_OS := windows
endif
-endif
ifeq ($(HOST_OS),)
$(error Unable to determine HOST_OS from uname -sm: $(UNAME)!)
diff --git a/core/tasks/kernel.mk b/core/tasks/kernel.mk
index d3419a0..a6942ca 100644
--- a/core/tasks/kernel.mk
+++ b/core/tasks/kernel.mk
@@ -58,7 +58,7 @@ ifeq "$(wildcard $(KERNEL_SRC) )" ""
$(warning * THIS IS DEPRECATED, AND WILL BE DISCONTINUED *)
$(warning * Please configure your device to download the kernel *)
$(warning * source repository to $(KERNEL_SRC))
- $(warning * See http://wiki.cyanogenmod.com/wiki/Integrated_kernel_building)
+ $(warning * See http://wiki.cyanogenmod.org/w/Doc:_integrated_kernel_building)
$(warning * for more information *)
$(warning ***************************************************************)
FULL_KERNEL_BUILD := false
diff --git a/envsetup.sh b/envsetup.sh
index 51f3420..07c481d 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -22,6 +22,7 @@ Invoke ". build/envsetup.sh" from your shell to add the following functions to y
- mkap: Builds the module(s) using mka and pushes them to the device.
- cmka: Cleans and builds using mka.
- reposync: Parallel repo sync using ionice and SCHED_BATCH.
+- repopick: Utility to fetch changes from Gerrit.
- installboot: Installs a boot.img to the connected device.
- installrecovery: Installs a recovery.img to the connected device.
@@ -1839,6 +1840,11 @@ alias mmmp='dopush mmm'
alias mkap='dopush mka'
alias cmkap='dopush cmka'
+function repopick() {
+ T=$(gettop)
+ $T/build/tools/repopick.py $@
+}
+
# Force JAVA_HOME to point to java 1.6 if it isn't already set
function set_java_home() {
diff --git a/tools/repopick.py b/tools/repopick.py
new file mode 100755
index 0000000..7336e78
--- /dev/null
+++ b/tools/repopick.py
@@ -0,0 +1,250 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2013 The CyanogenMod Project
+#
+# 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.
+#
+
+#
+# Run repopick.py -h for a description of this utility.
+#
+
+from __future__ import print_function
+
+import sys
+import json
+import os
+import subprocess
+import re
+import argparse
+import textwrap
+
+try:
+ # For python3
+ import urllib.request
+except ImportError:
+ # For python2
+ import imp
+ import urllib2
+ urllib = imp.new_module('urllib')
+ urllib.request = urllib2
+
+# Parse the command line
+parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, description=textwrap.dedent('''\
+ repopick.py is a utility to simplify the process of cherry picking
+ patches from CyanogenMod's Gerrit instance.
+
+ Given a list of change numbers, repopick will cd into the project path
+ and cherry pick the latest patch available.
+
+ With the --start-branch argument, the user can specify that a branch
+ should be created before cherry picking. This is useful for
+ cherry-picking many patches into a common branch which can be easily
+ abandoned later (good for testing other's changes.)
+
+ The --abandon-first argument, when used in conjuction with the
+ --start-branch option, will cause repopick to abandon the specified
+ branch in all repos first before performing any cherry picks.'''))
+parser.add_argument('change_number', nargs='+', help='change number to cherry pick')
+parser.add_argument('-i', '--ignore-missing', action='store_true', help='do not error out if a patch applies to a missing directory')
+parser.add_argument('-s', '--start-branch', nargs=1, help='start the specified branch before cherry picking')
+parser.add_argument('-a', '--abandon-first', action='store_true', help='before cherry picking, abandon the branch specified in --start-branch')
+parser.add_argument('-b', '--auto-branch', action='store_true', help='shortcut to "--start-branch auto --abandon-first --ignore-missing"')
+parser.add_argument('-q', '--quiet', action='store_true', help='print as little as possible')
+parser.add_argument('-v', '--verbose', action='store_true', help='print extra information to aid in debug')
+args = parser.parse_args()
+if args.start_branch == None and args.abandon_first:
+ parser.error('if --abandon-first is set, you must also give the branch name with --start-branch')
+if args.auto_branch:
+ args.abandon_first = True
+ args.ignore_missing = True
+ if not args.start_branch:
+ args.start_branch = ['auto']
+if args.quiet and args.verbose:
+ parser.error('--quiet and --verbose cannot be specified together')
+
+# Helper function to determine whether a path is an executable file
+def is_exe(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+# Implementation of Unix 'which' in Python
+#
+# From: http://stackoverflow.com/questions/377017/test-if-executable-exists-in-python
+def which(program):
+ fpath, fname = os.path.split(program)
+ if fpath:
+ if is_exe(program):
+ return program
+ else:
+ for path in os.environ["PATH"].split(os.pathsep):
+ path = path.strip('"')
+ exe_file = os.path.join(path, program)
+ if is_exe(exe_file):
+ return exe_file
+
+ return None
+
+# Simple wrapper for os.system() that:
+# - exits on error
+# - prints out the command if --verbose
+# - suppresses all output if --quiet
+def execute_cmd(cmd):
+ if args.verbose:
+ print('Executing: %s' % cmd)
+ if args.quiet:
+ cmd = cmd.replace(' && ', ' &> /dev/null && ')
+ cmd = cmd + " &> /dev/null"
+ if os.system(cmd):
+ if not args.verbose:
+ print('\nCommand that failed:\n%s' % cmd)
+ sys.exit(1)
+
+# Verifies whether pathA is a subdirectory (or the same) as pathB
+def is_pathA_subdir_of_pathB(pathA, pathB):
+ pathA = os.path.realpath(pathA) + '/'
+ pathB = os.path.realpath(pathB) + '/'
+ return(pathB == pathA[:len(pathB)])
+
+# Find the necessary bins - repo
+repo_bin = which('repo')
+if repo_bin == None:
+ repo_bin = os.path.join(os.environ["HOME"], 'repo')
+ if not is_exe(repo_bin):
+ sys.stderr.write('ERROR: Could not find the repo program in either $PATH or $HOME/bin\n')
+ sys.exit(1)
+
+# Find the necessary bins - git
+git_bin = which('git')
+if not is_exe(git_bin):
+ sys.stderr.write('ERROR: Could not find the git program in $PATH\n')
+ sys.exit(1)
+
+# Change current directory to the top of the tree
+if 'ANDROID_BUILD_TOP' in os.environ:
+ top = os.environ['ANDROID_BUILD_TOP']
+ if not is_pathA_subdir_of_pathB(os.getcwd(), top):
+ sys.stderr.write('ERROR: You must run this tool from within $ANDROID_BUILD_TOP!\n')
+ sys.exit(1)
+ os.chdir(os.environ['ANDROID_BUILD_TOP'])
+
+# Sanity check that we are being run from the top level of the tree
+if not os.path.isdir('.repo'):
+ sys.stderr.write('ERROR: No .repo directory found. Please run this from the top of your tree.\n')
+ sys.exit(1)
+
+# If --abandon-first is given, abandon the branch before starting
+if args.abandon_first:
+ # Determine if the branch already exists; skip the abandon if it does not
+ plist = subprocess.Popen([repo_bin,"info"], stdout=subprocess.PIPE)
+ needs_abandon = False
+ while(True):
+ pline = plist.stdout.readline().rstrip()
+ if not pline:
+ break
+ matchObj = re.match(r'Local Branches.*\[(.*)\]', pline.decode())
+ if matchObj:
+ local_branches = re.split('\s*,\s*', matchObj.group(1))
+ if any(args.start_branch[0] in s for s in local_branches):
+ needs_abandon = True
+ break
+
+ if needs_abandon:
+ # Perform the abandon only if the branch already exists
+ if not args.quiet:
+ print('Abandoning branch: %s' % args.start_branch[0])
+ cmd = '%s abandon %s' % (repo_bin, args.start_branch[0])
+ execute_cmd(cmd)
+ if not args.quiet:
+ print('')
+
+# Iterate through the requested change numbers
+for change in args.change_number:
+ if not args.quiet:
+ print('Applying change number %s ...' % change)
+
+ # Fetch information about the change from Gerrit's REST API
+ #
+ # gerrit returns two lines, a magic string and then valid JSON:
+ # )]}'
+ # [ ... valid JSON ... ]
+ url = 'http://review.cyanogenmod.org/changes/?q=%s&o=CURRENT_REVISION&o=CURRENT_COMMIT&pp=0' % change
+ if args.verbose:
+ print('Fetching from: %s\n' % url)
+ f = urllib.request.urlopen(url)
+ d = f.read().decode("utf-8")
+
+ # Parse the result
+ if args.verbose:
+ print('Result from request:\n' + d)
+ d = d.split('\n')[1]
+ d = re.sub(r'\[(.*)\]', r'\1', d)
+ data = json.loads(d)
+
+ # Extract information from the JSON response
+ project_name = data['project']
+ change_number = data['_number']
+ current_revision = data['revisions'][data['current_revision']]
+ patch_number = current_revision['_number']
+ fetch_url = current_revision['fetch']['http']['url']
+ fetch_ref = current_revision['fetch']['http']['ref']
+ author_name = current_revision['commit']['author']['name']
+ author_email = current_revision['commit']['author']['email']
+ author_date = current_revision['commit']['author']['date']
+ committer_name = current_revision['commit']['committer']['name']
+ committer_email = current_revision['commit']['committer']['email']
+ committer_date = current_revision['commit']['committer']['date']
+ subject = current_revision['commit']['subject']
+
+ # Get the list of projects that repo knows about
+ # - convert the project name to a project path
+ plist = subprocess.Popen([repo_bin,"list"], stdout=subprocess.PIPE)
+ while(True):
+ pline = plist.stdout.readline().rstrip()
+ if not pline:
+ break
+ ppaths = re.split('\s*:\s*', pline.decode())
+ if ppaths[1] == project_name:
+ project_path = ppaths[0]
+ break
+ if 'project_path' not in locals():
+ sys.stderr.write('ERROR: Could not determine the project path for project %s\n' % project_name)
+ sys.exit(1)
+
+ # Check that the project path exists
+ if not os.path.isdir(project_path):
+ if args.ignore_missing:
+ print('WARNING: Skipping %d since there is no project directory: %s\n' % (change_number, project_path))
+ continue;
+ else:
+ sys.stderr.write('ERROR: For %d, there is no project directory: %s\n' % (change_number, project_path))
+ sys.exit(1)
+
+ # If --start-branch is given, create the branch (more than once per path is okay; repo ignores gracefully)
+ if args.start_branch:
+ cmd = '%s start %s %s' % (repo_bin, args.start_branch[0], project_path)
+ execute_cmd(cmd)
+
+ # Print out some useful info
+ if not args.quiet:
+ print('--> Subject: "%s"' % subject)
+ print('--> Project path: %s' % project_path)
+ print('--> Change number: %d (Patch Set %d)' % (change_number, patch_number))
+ print('--> Author: %s <%s> %s' % (author_name, author_email, author_date))
+ print('--> Committer: %s <%s> %s' % (committer_name, committer_email, committer_date))
+
+ # Perform the cherry-pick
+ cmd = 'cd %s && git fetch %s %s && git cherry-pick FETCH_HEAD' % (project_path, fetch_url, fetch_ref)
+ execute_cmd(cmd)
+ if not args.quiet:
+ print('')
+