#!/bin/bash -eu # # Copyright 2021 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. USAGE=\ 'Usage: upstream-workon [-h] init link build install clean help' set +e read -r -d '' HELP <<'EOF' Usage: upstream-workon [-h] init link build install clean help Flags: -h --help Print this help message Commands: init Initialize in a developer workdir using a new tree link Link an existing developer source dir to portage workdir build Build the package using ebuild ... compile install Install the package using ebuild ... install clean Clean up your work without deleting the developer workdir help Print this help message Examples: # Start work mkdir "$HOME/llvm" upstream-workon init sys-devel/llvm "$HOME/llvm" # Link your existing work upstream-workon link sys-devel/llvm "$HOME/llvm" # Compile your work upstream-workon build sys-devel/llvm # Install your changes to the chroot upstream-workon install sys-devel/llvm # Clean up upstream-workon clean sys-devel/llvm EOF set -e incorrect_number_of_arguments() { echo 'ERROR: Please use correct command syntax' >&2 echo "${USAGE}" >&2 exit 1 } print_experimental_warning() { echo >&2 echo '!!! WARNING: This tool is EXPERIMENTAL--please do not rely on the API.' >&2 echo '!!! WARNING: Please recommend new features for Version 2, but this' >&2 echo '!!! WARNING: implementation will not be actively developed and' >&2 echo '!!! WARNING: exists only to receive feedback and minor fixes.' >&2 } # ------------------------------------------------------------------------------ # Actual logic # ------------------------------------------------------------------------------ # We probably can just pass through "USE", but I think this gives a bit more # flexibility in the future. USE_FLAGS="${USE:-}" if [[ -n "${USE_FLAGS}" ]]; then echo 'USE flags set to:' echo " ${USE_FLAGS}" fi init() { local package="$1" local desired_src_loc="$2" local ebuild_loc ebuild_loc="$(resolve_ebuild_for "${package}")" local ebuild_name ebuild_name="$(basename "${ebuild_loc}" | sed 's/\.ebuild$//g')" local package_name # SC2001 complains about not using variable replace syntax. # However, variable remove syntax is not sufficiently expansive # to do this replacement easily. # shellcheck disable=2001 package_name="$(sed 's/-r[0-9]\+$//g' <<< "${ebuild_name}")" local ebuild_category ebuild_category="$(basename "$(dirname "$(dirname "${ebuild_loc}")")")" local portage_dir='/var/tmp/portage' local work_dir="${portage_dir}/${ebuild_category}/${ebuild_name}/work/${package_name}" ebuild "${ebuild_loc}" clean USE="${USE_FLAGS}" ebuild "${ebuild_loc}" unpack # May need to init git if it doesn't already exist. # Probably could just use git -C instead of the pushd/popd. pushd "${work_dir}" >& /dev/null if [[ ! -d '.git' ]]; then git init git add . git commit -m 'Initial commit' fi popd >& /dev/null USE="${USE_FLAGS}" ebuild "${ebuild_loc}" configure cp -r -p "${work_dir}/." "${desired_src_loc}" local backup_dir="${work_dir}.bk" mv "${work_dir}" "${backup_dir}" ln -s "$(realpath "${desired_src_loc}")" "${work_dir}" pushd "${desired_src_loc}" >& /dev/null git add . git commit -m 'Ebuild configure commit' popd >& /dev/null echo echo '----------------------------------------' echo 'Successfully created local mirror!' echo "Developer work directory set up at: ${desired_src_loc}" echo 'To build the package, run:' echo " upstream-workon build ${package}" echo 'To install the package, run:' echo " sudo upstream-workon install ${package}" echo "To clean up (without deleting ${desired_src_loc}), run:" echo " upstream-workon clean ${package}" echo "WARNING: Moving original workdir to ${backup_dir}, consider deleting" >&2 } clean() { local package="$1" echo 'WARNING: You may need to run this with sudo' >&2 local ebuild_loc ebuild_loc="$(resolve_ebuild_for "${package}")" ebuild "${ebuild_loc}" clean echo '----------------------------------------' echo "Successfully cleaned up ${package}!" } compile() { local package="$1" local ebuild_loc ebuild_loc="$(resolve_ebuild_for "${package}")" USE="${USE_FLAGS}" ebuild "${ebuild_loc}" compile echo '----------------------------------------' echo "Successfully compiled ${package}!" } install_src() { local package="$1" echo 'WARNING: You may need to run this with sudo' >&2 local ebuild_loc ebuild_loc="$(resolve_ebuild_for "${package}")" USE="${USE_FLAGS}" ebuild "${ebuild_loc}" install echo '----------------------------------------' echo "Successfully installed ${package}!" } link_src() { local package="$1" local desired_src_loc="$2" local ebuild_loc ebuild_loc="$(resolve_ebuild_for "${package}")" local ebuild_name ebuild_name="$(basename "${ebuild_loc}" | sed 's/\.ebuild$//g')" local package_name # shellcheck disable=2001 package_name="$(sed 's/-r[0-9]\+$//g' <<< "${ebuild_name}")" local ebuild_category ebuild_category="$(basename "$(dirname "$(dirname "${ebuild_loc}")")")" local portage_dir='/var/tmp/portage' local work_dir="${portage_dir}/${ebuild_category}/${ebuild_name}/work/${package_name}" local backup_dir="${work_dir}.bk" # Because of some annoying permissions issues, we have to configure directly in # /var/tmp/portage/... # We then copy over those changes into our local source directory. # To make sure the proper deletions get done, we delete everything except # your local git directory. ebuild "${ebuild_loc}" clean USE="${USE_FLAGS}" ebuild "${ebuild_loc}" configure # TODO(ajordanr): This is a rough edge, and I don't want users to delete their # home directory without knowing what they are doing. So we're copying # everything instead. # TODO(ajordanr): This will ignore git submodules, which I don't want. mv "${desired_src_loc}" "${desired_src_loc}.bk" mkdir "${desired_src_loc}" cp -rP "${desired_src_loc}.bk/.git" "${desired_src_loc}/.git" rsync -a --exclude=".git" "${work_dir}"/* "${desired_src_loc}" rsync -a --exclude=".git" "${work_dir}"/.[^.]* "${desired_src_loc}" mv "${work_dir}" "${backup_dir}" ln -s "$(realpath "${desired_src_loc}")" "${work_dir}" echo '----------------------------------------' echo 'Successfully linked to local mirror!' echo "Developer work directory linked to: ${desired_src_loc}" echo "WARNING: Moving original workdir to ${backup_dir}, consider deleting" >&2 echo "WARNING: Moving original dev dir to ${desired_src_loc}.bk, consider deleting" >&2 } resolve_ebuild_for() { equery w "$1" } CMD="${1:-}" case "${CMD}" in -h|--help|help) shift echo "${HELP}" print_experimental_warning exit 1 ;; init) shift [[ -z "${1:-}" || -z "${2:-}" ]] && incorrect_number_of_arguments print_experimental_warning init "$1" "$2" ;; link) shift [[ -z "${1:-}" || -z "${2:-}" ]] && incorrect_number_of_arguments print_experimental_warning link_src "$1" "$2" ;; build) shift [[ -z "${1:-}" ]] && incorrect_number_of_arguments print_experimental_warning compile "$1" ;; clean) shift [[ -z "${1:-}" ]] && incorrect_number_of_arguments print_experimental_warning clean "$1" ;; install) shift [[ -z "${1:-}" ]] && incorrect_number_of_arguments print_experimental_warning install_src "$1" ;; *) incorrect_number_of_arguments ;; esac