#!/bin/bash # Copyright (c) 2010 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. # This script moves ebuilds between 'stable' and 'live' states. # By default 'stable' ebuilds point at and build from source at the # last known good commit. Moving an ebuild to 'live' (via cros_workon start) # is intended to support development. The current source tip is fetched, # source modified and built using the unstable 'live' (9999) ebuild. # --- BEGIN COMMON.SH BOILERPLATE --- # Load common CrOS utilities. Inside the chroot this file is installed in # /usr/lib/crosutils. Outside the chroot we find it relative to the script's # location. find_common_sh() { local common_paths=(/usr/lib/crosutils $(dirname "$(readlink -f "$0")")) local path SCRIPT_ROOT= for path in "${common_paths[@]}"; do if [ -r "${path}/common.sh" ]; then SCRIPT_ROOT=${path} break fi done } find_common_sh . "${SCRIPT_ROOT}/common.sh" || (echo "Unable to load common.sh" && exit 1) # --- END COMMON.SH BOILERPLATE --- # Script must be run inside the chroot restart_in_chroot_if_needed "$@" get_default_board DEFINE_string board "${DEFAULT_BOARD}" \ "The board to set package keywords for." DEFINE_boolean host "${FLAGS_FALSE}" \ "Uses the host instead of board" DEFINE_string command "git status" \ "The command to be run by forall." DEFINE_boolean all "${FLAGS_FALSE}" \ "Apply to all possible packages for the given command" FLAGS_HELP="usage: $0 [flags] [|--all] commands: start: Moves an ebuild to live (intended to support development) stop: Moves an ebuild to stable (use last known good) list: List of live ebuilds (workon ebuilds if --all) list-all: List all of the live ebuilds for all setup boards iterate: For each ebuild, cd to the source dir and run a commond" FLAGS "$@" || exit 1 eval set -- "${FLAGS_ARGV}" # eat the workon command keywords: start, stop or list. WORKON_CMD=$1 shift # Board dir config # If both are specified, just use host, because board does not # have to be specified and may come from default, in which case # there's no way to override. [ -n "${FLAGS_board}" ] && [ "${FLAGS_host}" = ${FLAGS_TRUE} ] && \ FLAGS_board="" # kill board [ -z "${FLAGS_board}" ] && [ "${FLAGS_host}" = ${FLAGS_FALSE} ] && \ [ "${WORKON_CMD}" != "list-all" ] && \ die "You must specify either --host or --board=" if [ -n "${FLAGS_board}" ]; then BOARD_DIR=/build/"${FLAGS_board}" # --board specified EQUERYCMD=equery-"${FLAGS_board}" EBUILDCMD=ebuild-"${FLAGS_board}" PORTAGEQCMD=portageq-"${FLAGS_board}" BOARD_STR="${FLAGS_board}" BOARD_KEYWORD="$(portageq-${FLAGS_board} envvar ARCH)" else BOARD_DIR="" # --host specified EQUERYCMD=equery EBUILDCMD=ebuild PORTAGEQCMD=portageq BOARD_STR="host" BOARD_KEYWORD="$(portageq envvar ARCH)" fi WORKON_DIR=${CHROOT_TRUNK_DIR}/.config/cros_workon KEYWORDS_DIR=${BOARD_DIR}/etc/portage/package.keywords UNMASK_DIR=${BOARD_DIR}/etc/portage/package.unmask WORKON_FILE=${WORKON_DIR}/${FLAGS_board:-host} KEYWORDS_FILE=${KEYWORDS_DIR}/cros-workon UNMASK_FILE=${UNMASK_DIR}/cros-workon # TODO(msb): remove the backward compatibility after 10/01/2010 if [ -d "${WORKON_DIR}" ]; then sudo chown -R "${USER}" "${WORKON_DIR}" fi mkdir -p "${WORKON_DIR}" || die "mkdir -p ${WORKON_DIR}" touch "${WORKON_FILE}" || die "touch ${WORKON_FILE}" sudo mkdir -p "${KEYWORDS_DIR}" "${UNMASK_DIR}" || \ die "mkdir -p ${KEYWORDS_DIR} ${UNMASK_DIR}" if [ ! -L "${KEYWORDS_FILE}" ]; then sudo rm -f "${KEYWORDS_FILE}" sudo ln -s "${WORKON_FILE}" "${KEYWORDS_FILE}" || \ die "ln -s ${WORKON_FILE} ${KEYWORDS_FILE}" fi if [ ! -L "${UNMASK_FILE}" ]; then [ -f "${UNMASK_FILE}" ] && sudo mv "${UNMASK_FILE}" "${WORKON_FILE}" sudo ln -s "${WORKON_FILE}" "${UNMASK_FILE}" || \ die "ln -s ${WORKON_FILE} ${UNMASK_FILE}" fi find_keyword_workon_ebuilds() { local keyword="${1}" local overlay local cros_overlays=$("${PORTAGEQCMD}" envvar PORTDIR_OVERLAY) # NOTE: overlay may be a symlink, and we have to use ${overlay}/ for overlay in ${cros_overlays}; do # only look up ebuilds named 9999 to eliminate duplicates find ${overlay}/ -name '*9999.ebuild' | \ xargs grep -l "inherit.*cros-workon" | \ xargs grep -l "KEYWORDS=.*${keyword}.*" done } show_workon_ebuilds() { local keyword=$1 find_keyword_workon_ebuilds ${keyword} | \ sed -e 's/.*\/\([^/]*\)\/\([^/]*\)\/.*\.ebuild/\1\/\2/' | \ sort -u # This changes the absolute path to ebuilds into category/package. } # Canonicalize package name to category/package. canonicalize_name () { local pkgfile local pkgname if grep -qx "=$1-9999" "${WORKON_FILE}" ; then echo $1 return 0 fi if ! pkgfile=$(ACCEPT_KEYWORDS="~${BOARD_KEYWORD}" ${EQUERYCMD} which $1); then warn "error looking up package $1" 1>&2 return 1 fi pkgname=$(\ echo "${pkgfile}" |awk -F '/' '{ print $(NF-2) "/" $(NF-1) }') if ! grep -q "cros-workon" ${pkgfile}; then warn "${pkgname} is not a cros-workon package" 1>&2 return 1 fi echo "${pkgname}" return 0 } # Canonicalize a list of names. canonicalize_names () { local atoms=$1 local names="" local atom for atom in ${atoms}; do local name=$(canonicalize_name "${atom}") [ -n "${name}" ] || return 1 names+=" ${name}" done echo "${names}" } # Display ebuilds currently part of the live branch and open for development. show_live_ebuilds () { sed -n 's/^=\(.*\)-9999$/\1/p' "${WORKON_FILE}" } # Display ebuilds currently part of the live branch and open for development # for any board that currently has live ebuilds. show_all_live_ebuilds () { local workon_file for workon_file in ${WORKON_DIR}/*; do if [ -s "${workon_file}" ]; then echo -e "${V_BOLD_GREEN}$(basename ${workon_file}):${V_VIDOFF}" sed -n 's/^=\(.*\)-9999$/ \1/p' "${workon_file}" echo "" fi done } # This is called only for "cros-workon start". We dont handle the # "stop" case since the local changes are ignored anyway since the # 9999.ebuild is masked and we dont want to deal with what to do with # the user's local changes. regen_manifest_and_sync() { # Nothing to do unless you are working on the minilayout local manifest=${CHROOT_TRUNK_DIR}/.repo/manifest.xml if [ $(basename $(readlink -f ${manifest})) != "minilayout.xml" ]; then return fi local pkgname for pkgname in $(show_live_ebuilds); do eval $(${EBUILDCMD} $(${EQUERYCMD} which ${pkgname}) info) local srcdir=$(readlink -m ${CROS_WORKON_SRCDIR}) local trunkdir=$(readlink -m ${CHROOT_TRUNK_DIR}) local project_path=${srcdir#${trunkdir}/} loman add --workon "${CROS_WORKON_PROJECT}" "${project_path}" done echo "Please run \"repo sync\" now." } # Move a stable ebuild to the live development catgeory. The ebuild # src_unpack step fetches the package source for local development. ebuild_to_live () { local atoms=$1 local atoms_success="" local atom for atom in ${atoms}; do if ! grep -qx "=${atom}-9999" "${WORKON_FILE}" ; then if sudo bash -c "echo \"=${atom}-9999\" >> \"${WORKON_FILE}\""; then atoms_success="${atoms_success} ${atom}" fi else warn "Already working on ${atom}" fi done [ -n "${atoms_success}" ] && regen_manifest_and_sync && \ info "Started working on '${atoms_success/ /}' for '${BOARD_STR}'" } # Move a live development ebuild back to stable. ebuild_to_stable () { local atoms=$1 local atoms_success="" local atom for atom in ${atoms}; do if grep -qx "=${atom}-9999" "${WORKON_FILE}" ; then if sudo sed -e "/^=${atom/\//\\/}-9999\$/d" -i "${WORKON_FILE}"; then atoms_success="${atoms_success} ${atom}" fi else warn "Not working on ${atom}" fi done [ -n "${atoms_success}" ] && \ info "Stopped working on '${atoms_success/ /}' for '${BOARD_STR}'" } # Run a command on all or a set of repos. ebuild_iterate() { local atoms=$1 local atom for atom in ${atoms}; do info "Running \"${FLAGS_command}\" on ${atom}" eval $(${EBUILDCMD} $(${EQUERYCMD} which ${atom}) info) (cd "${CROS_WORKON_SRCDIR}" && bash -c "${FLAGS_command}") done } # --all makes commands operate on different lists if [ ${FLAGS_all} = "${FLAGS_TRUE}" ]; then case ${WORKON_CMD} in start) ATOM_LIST=$(show_workon_ebuilds ${BOARD_KEYWORD});; stop|iterate) ATOM_LIST=$(show_live_ebuilds);; list) ;; *) die "--all is invalid for the given command";; esac else # not selected --all case ${WORKON_CMD} in start|stop|iterate) ATOM_LIST=$@ if [ -z "${ATOM_LIST}" ]; then die "${WORKON_CMD}: No packages specified" elif ! ATOM_LIST=$(canonicalize_names "${ATOM_LIST}"); then die "Error parsing package list" fi;; *) ;; esac fi case ${WORKON_CMD} in start) ebuild_to_live "${ATOM_LIST}" ;; stop) ebuild_to_stable "${ATOM_LIST}" ;; list) [ ${FLAGS_all} = "${FLAGS_FALSE}" ] && show_live_ebuilds || \ show_workon_ebuilds ${BOARD_KEYWORD} ;; list-all) show_all_live_ebuilds ;; iterate) ebuild_iterate "${ATOM_LIST}" ;; *) die "$(basename $0): command '${WORKON_CMD}' not recognized" ;; esac