cros_workon: Handle workon-only packages.

This adds a --workon_only flag, which maps to the subset of --all
packages that have nothing but 9999 ebuild (i.e. no stable). This flag
can be used in conjunction with:

 start, info, list ==> applies to all workon-only packages

 stop, iterate ==> applies to all live packages that are workon-only

The implementation is quite inefficient because, for each atom found for
the --all set, it will scan all overlays looking for a stable (non-9999)
ebuild. This can probably be improved if need arises, by combining these
two scans into one.

BUG=brillo:634
TEST=Manually tested all command/flag combinations.

Change-Id: Id8276072e8a5a9a772baecbc893a4c7092d2de78
Reviewed-on: https://chromium-review.googlesource.com/262334
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Commit-Queue: Gilad Arnold <garnold@chromium.org>
Tested-by: Gilad Arnold <garnold@chromium.org>
diff --git a/cros_workon b/cros_workon
index db9d953..bdc9d94 100755
--- a/cros_workon
+++ b/cros_workon
@@ -30,6 +30,8 @@
   "The command to be run by forall."
 DEFINE_boolean all "${FLAGS_FALSE}" \
   "Apply to all possible packages for the given command"
+DEFINE_boolean workon_only "${FLAGS_FALSE}" \
+  "Apply to packages that have a workon ebuild only"
 
 FLAGS_HELP="usage: $0 <command> [flags] [<list of packages>|.|--all]
 commands:
@@ -175,6 +177,22 @@
   find_keyword_workon_ebuilds "${keyword}" | ebuild_to_package | sort -u
 }
 
+# Prints only the atoms that have nothing but 9999 ebuilds across all overlays.
+filter_workon_only() {
+  local atoms="$1"
+  local atom
+  local num_ebuilds
+  local overlay
+  for atom in ${atoms}; do
+    num_ebuilds=0
+    for overlay in "${OVERLAYS[@]}"; do
+      num_ebuilds=$(ls -1 "${overlay}"/${atom}/*.ebuild 2>/dev/null | wc -l)
+      [[ "${num_ebuilds}" -gt 1 ]] && break
+    done
+    [[ "${num_ebuilds}" -le 1 ]] && echo ${atom}
+  done
+}
+
 show_workon_info() {
    local atoms="$1"
    local keyword="$2"
@@ -392,9 +410,13 @@
   done
 }
 
+unset use_list
+[[ ${FLAGS_workon_only} = ${FLAGS_TRUE} ]] && use_list="--workon_only"
+[[ ${FLAGS_all} = ${FLAGS_TRUE} ]] && use_list="--all"
+
 # Only call portageq when absolutely required, and when we do, only run it
 # once -- it's a slow beast and can easily take hundreds of milliseconds :(.
-if [[ ${WORKON_CMD} != "list" || ${FLAGS_all} != ${FLAGS_FALSE} ]] ; then
+if [[ ${WORKON_CMD} != "list" || -n "${use_list}" ]] ; then
   ARCH=$(${PORTAGEQCMD} envvar ARCH)
   cmd=( cros_list_overlays )
   if [[ -n "${FLAGS_brick}" ]]; then
@@ -408,15 +430,22 @@
   OVERLAYS=( $("${cmd[@]}") )
 fi
 
-# --all makes commands operate on different lists
-if [ ${FLAGS_all} = "${FLAGS_TRUE}" ]; then
+# --all and --workon_only make commands operate on different lists.
+if [[ -n "${use_list}" ]]; then
   case ${WORKON_CMD} in
-    start|info) ATOM_LIST=$(show_workon_ebuilds ${ARCH});;
-    stop|iterate) ATOM_LIST=$(show_live_ebuilds);;
-    list) ;;
-    *) die "--all is invalid for the given command";;
+    start|info|list)
+      ATOM_LIST=$(show_workon_ebuilds ${ARCH})
+      if [[ "${use_list}" = "--workon_only" ]]; then
+        ATOM_LIST=$(filter_workon_only "${ATOM_LIST}")
+      fi;;
+    stop|iterate)
+      ATOM_LIST=$(show_live_ebuilds)
+      if [[ "${use_list}" = "--workon_only" ]]; then
+        ATOM_LIST=$(filter_workon_only "${ATOM_LIST}")
+      fi;;
+    *) die "${use_list} is invalid for the given command";;
   esac
-else # not selected --all
+else
   case ${WORKON_CMD} in
     start|stop|info|iterate)
       ATOM_LIST=$@
@@ -437,8 +466,12 @@
   start) ebuild_to_live "${ATOM_LIST}" ;;
   stop) ebuild_to_stable "${ATOM_LIST}" ;;
   info) show_workon_info "${ATOM_LIST}" "${ARCH}" ;;
-  list) [ ${FLAGS_all} = "${FLAGS_FALSE}" ] && show_live_ebuilds || \
-    show_workon_ebuilds ${ARCH} ;;
+  list)
+    if [[ -n "${use_list}" ]]; then
+      for atom in ${ATOM_LIST}; do echo ${atom}; done
+    else
+      show_live_ebuilds
+    fi;;
   list-all) show_all_live_ebuilds ;;
   iterate) ebuild_iterate "${ATOM_LIST}" ;;
   *)