| Index: gmerge
|
| diff --git a/gmerge b/gmerge
|
| index e6426d0ffede672e7c2aeb257b35ed4e9efa08ad..363233f187c91e1cd538939322e8fb8624937be4 100755
|
| --- a/gmerge
|
| +++ b/gmerge
|
| @@ -1,83 +1,134 @@
|
| -#!/bin/bash
|
| +#!/usr/bin/env python
|
|
|
| -# Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved.
|
| +# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| -# Prints the arguments and dies.
|
| -print_and_die() {
|
| - echo $*
|
| - exit 1
|
| -}
|
| -
|
| -# Set up PORTAGE variables to be rooted in /usr/local/portage.
|
| -setup_portage_vars() {
|
| - export PORTDIR=/usr/local/portage
|
| - export PKGDIR=/usr/local/portage
|
| - export DISTDIR=/usr/local/portage/distfiles
|
| - export PORTAGE_BINHOST="${DEVKIT_URL}/static/pkgroot/${BOARD_NAME}/packages"
|
| - export PORTAGE_TMPDIR=/tmp
|
| - export CONFIG_PROTECT="-*"
|
| - export FEATURES="-sandbox"
|
| - # Accept keywords only for stable ebuilds by default.
|
| - [ -z "$ACCEPT_KEYWORDS" ] && ACCEPT_KEYWORDS="arm x86 ~arm ~x86"
|
| - export ACCEPT_KEYWORDS
|
| - export ROOT=/
|
| -}
|
| -
|
| -# Prompts the user to change the root to /usr/local.
|
| -change_portage_root() {
|
| - read -p "Do you wish to install this program into /usr/local? (Y/n) " input
|
| - if [[ ${input} = [Nn]* ]]; then
|
| - echo "Better safe than sorry."
|
| - exit 1
|
| - fi
|
| - export ROOT=/usr/local
|
| -}
|
| -
|
| -set -e
|
| -
|
| -# Get variables for the devserver from the lsb-release file.
|
| -DEVKIT_URL=$(grep ^CHROMEOS_DEVSERVER /etc/lsb-release | cut -d = -f 2-)
|
| -BOARD_NAME=$(grep ^CHROMEOS_RELEASE_BOARD /etc/lsb-release | cut -d = -f 2-)
|
| -[ -z "${BOARD_NAME}" ] && print_and_die "No board in /etc/lsb-release"
|
| -[ -z "${DEVKIT_URL}" ] && print_and_die "No dev server url in /etc/lsb-release"
|
| -
|
| -setup_portage_vars
|
| -
|
| -# Determine if we should send a build command to the devserver.
|
| -BUILD=1
|
| -if [ x$1 == x-n ]; then
|
| - BUILD=0
|
| - shift
|
| -fi
|
| -
|
| -# Package name is the last argument.
|
| -# TODO(sosa) - Support multiple packages.
|
| -PACKAGE_NAME=${!#}
|
| -
|
| -# If no package name is provided skip to emerge options.
|
| -[[ ${PACKAGE_NAME} == -* ]] && BUILD=0
|
| -
|
| -mount -o remount,rw / || change_portage_root
|
| -
|
| -# Re-mount /tmp as exec.
|
| -mount -o remount,exec /tmp
|
| -trap "mount -o remount,noexec /tmp" EXIT
|
| -
|
| -# Delete the local binary package cache.
|
| -rm -rf "${PKGDIR}/packages"
|
| -
|
| -if [ ${BUILD} == 1 ]; then
|
| - echo "Building ${PACKAGE_NAME}"
|
| - ESCAPED_PACKAGE=$(python -c \
|
| - "import urllib; print urllib.quote('''${PACKAGE_NAME}''')")
|
| - ESCAPED_BOARD=$(python -c \
|
| - "import urllib; print urllib.quote('''${BOARD_NAME}''')")
|
| -
|
| - wget $DEVKIT_URL/build \
|
| - --post-data="pkg=${ESCAPED_PACKAGE}&board=${ESCAPED_BOARD}"
|
| -fi
|
| -
|
| -echo "Emerging ${PACKAGE_NAME}"
|
| -emerge --getbinpkgonly --usepkgonly "$@"
|
| +"""Build packages on a host machine, then install them on the local target.
|
| +
|
| +Contacts a devserver (trunk/src/platform/dev/devserver.py) and
|
| +requests that it build a package, then performs a binary install of
|
| +that package on the local machine.
|
| +"""
|
| +
|
| +import optparse
|
| +import os
|
| +import shutil
|
| +import subprocess
|
| +import sys
|
| +import urllib
|
| +import urllib2
|
| +
|
| +
|
| +class GMerger(object):
|
| + """emerges a package from the devserver.
|
| +
|
| + NB: Must be instantiated using with, e.g.:
|
| + with GMerger(open('/etc/lsb-release').readlines()) as merger:
|
| + in order to remount /tmp as executable.
|
| + """
|
| +
|
| + def __init__(self, lsb_release_lines):
|
| + self.lsb_release = self.ParseLsbRelease(lsb_release_lines)
|
| + try:
|
| + self.devkit_url = self.lsb_release['CHROMEOS_DEVSERVER']
|
| + self.board_name = self.lsb_release['CHROMEOS_RELEASE_BOARD']
|
| + except KeyError, e:
|
| + sys.exit('Could not find /etc/lsb_release value: ' + e)
|
| +
|
| + def RemountOrChangeRoot(self, environ):
|
| + """Remount the root filesystem rw; install into /usr/local if this fails."""
|
| + rc = subprocess.call(['mount', '-o', 'remount,rw', '/'])
|
| + if rc == 0:
|
| + return
|
| + answer = raw_input(
|
| + 'Could not mount / as writable. Install into /usr/local? (Y/n)')
|
| + if answer[0] not in 'Yy':
|
| + sys.exit('Better safe than sorry.')
|
| + environ['ROOT'] = '/usr/local'
|
| +
|
| + def ParseLsbRelease(self, lsb_release_lines):
|
| + """Convert a list of KEY=VALUE lines to a dictionary."""
|
| + partitioned_lines = [line.rstrip().partition('=')
|
| + for line in lsb_release_lines]
|
| + return dict([(fields[0], fields[2]) for fields in partitioned_lines])
|
| +
|
| + def SetupPortageEnvironment(self, environ):
|
| + """Setup portage to use stateful partition and fetch from dev server."""
|
| + environ.update({
|
| + 'PORTDIR': '/usr/local/portage',
|
| + 'PKGDIR': '/usr/local/portage',
|
| + 'DISTDIR': '/usr/local/portage/distfiles',
|
| + 'PORTAGE_BINHOST': '%s/static/pkgroot/%s/packages' % (
|
| + self.devkit_url, self.board_name),
|
| + 'PORTAGE_TMPDIR': '/tmp',
|
| + 'CONFIG_PROTECT': '-*',
|
| + 'FEATURES': '-sandbox',
|
| + 'ACCEPT_KEYWORDS': 'arm x86 ~arm ~x86',
|
| + 'ROOT': '/',
|
| + })
|
| +
|
| + def GeneratePackageRequest(self, package_name):
|
| + """Build the POST string that conveys our options to the devserver."""
|
| + post_data = {'board': self.board_name,
|
| + 'pkg': package_name,
|
| + 'use': FLAGS.use,
|
| + 'accept_stable': FLAGS.accept_stable,
|
| + }
|
| + post_data = dict([(key, value) for (key, value) in post_data.iteritems()
|
| + if value])
|
| + return urllib.urlencode(post_data)
|
| +
|
| + def RequestPackageBuild(self, package_name):
|
| + """Contacts devserver to request a build."""
|
| + try:
|
| + result = urllib2.urlopen(self.devkit_url + '/build',
|
| + data=self.GeneratePackageRequest(package_name))
|
| + print result.read()
|
| + result.close()
|
| +
|
| + except urllib2.HTTPError, e:
|
| + # The exception includes the content, which is the error mesage
|
| + sys.exit(e.read())
|
| +
|
| +
|
| +def main():
|
| + global FLAGS
|
| + parser = optparse.OptionParser(usage='usage: %prog [options] package_name')
|
| + parser.add_option('--accept_stable',
|
| + action='store_true', dest='accept_stable', default=False,
|
| + help=('Build even if a cros_workon package is not '
|
| + 'using the live package'))
|
| + parser.add_option('-n', '--no_devserver',
|
| + action='store_false', dest='call_devserver', default=True,
|
| + help='Do not actually ask the server to build')
|
| + parser.add_option('--use', '--USE',
|
| + dest='use', default=None,
|
| + help='USE flags to pass to emerge on the server')
|
| +
|
| + (FLAGS, remaining_arguments) = parser.parse_args()
|
| + if len(remaining_arguments) != 1:
|
| + parser.print_help()
|
| + sys.exit('Need exactly one package name')
|
| +
|
| + package_name = remaining_arguments[0]
|
| +
|
| + try:
|
| + subprocess.check_call(['mount', '-o', 'remount,exec', '/tmp'])
|
| + merger = GMerger(open('/etc/lsb-release').readlines())
|
| + merger.SetupPortageEnvironment(os.environ)
|
| + merger.RemountOrChangeRoot(os.environ)
|
| + if FLAGS.call_devserver:
|
| + merger.RequestPackageBuild(package_name)
|
| + else:
|
| + print 'Not requesting fresh build on server---installing whatever we find'
|
| +
|
| + print 'Emerging ', package_name
|
| + subprocess.check_call([
|
| + 'emerge', '--getbinpkgonly', '--usepkgonly', package_name])
|
| + finally:
|
| + subprocess.call(['mount', '-o', 'remount,noexec', '/tmp'])
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + main()
|
|
|