1#!/bin/bash -eu 2# 3# Copyright 2021 The ChromiumOS Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7USAGE=\ 8'Usage: upstream-workon [-h] 9 init <PACKAGE> <DEV_WORK_DIR> 10 link <PACKAGE> <DEV_WORK_DIR> 11 build <PACKAGE> 12 install <PACKAGE> 13 clean <PACKAGE> 14 help' 15 16set +e 17read -r -d '' HELP <<'EOF' 18Usage: upstream-workon [-h] 19 init <PACKAGE> <DEV_WORK_DIR> 20 link <PACKAGE> <DEV_WORK_DIR> 21 build <PACKAGE> 22 install <PACKAGE> 23 clean <PACKAGE> 24 help 25 26Flags: 27 -h --help Print this help message 28 29Commands: 30 init Initialize in a developer workdir using a new tree 31 link Link an existing developer source dir to portage workdir 32 build Build the package using ebuild ... compile 33 install Install the package using ebuild ... install 34 clean Clean up your work without deleting the developer workdir 35 help Print this help message 36 37Examples: 38 39 # Start work 40 mkdir "$HOME/llvm" 41 upstream-workon init sys-devel/llvm "$HOME/llvm" 42 43 # Link your existing work 44 upstream-workon link sys-devel/llvm "$HOME/llvm" 45 46 # Compile your work 47 upstream-workon build sys-devel/llvm 48 49 # Install your changes to the chroot 50 upstream-workon install sys-devel/llvm 51 52 # Clean up 53 upstream-workon clean sys-devel/llvm 54 55EOF 56set -e 57 58incorrect_number_of_arguments() { 59 echo 'ERROR: Please use correct command syntax' >&2 60 echo "${USAGE}" >&2 61 exit 1 62} 63 64print_experimental_warning() { 65 echo >&2 66 echo '!!! WARNING: This tool is EXPERIMENTAL--please do not rely on the API.' >&2 67 echo '!!! WARNING: Please recommend new features for Version 2, but this' >&2 68 echo '!!! WARNING: implementation will not be actively developed and' >&2 69 echo '!!! WARNING: exists only to receive feedback and minor fixes.' >&2 70} 71 72# ------------------------------------------------------------------------------ 73# Actual logic 74# ------------------------------------------------------------------------------ 75 76# We probably can just pass through "USE", but I think this gives a bit more 77# flexibility in the future. 78USE_FLAGS="${USE:-}" 79 80if [[ -n "${USE_FLAGS}" ]]; then 81 echo 'USE flags set to:' 82 echo " ${USE_FLAGS}" 83fi 84 85init() { 86 local package="$1" 87 local desired_src_loc="$2" 88 local ebuild_loc 89 ebuild_loc="$(resolve_ebuild_for "${package}")" 90 91 local ebuild_name 92 ebuild_name="$(basename "${ebuild_loc}" | sed 's/\.ebuild$//g')" 93 local package_name 94 # SC2001 complains about not using variable replace syntax. 95 # However, variable remove syntax is not sufficiently expansive 96 # to do this replacement easily. 97 # shellcheck disable=2001 98 package_name="$(sed 's/-r[0-9]\+$//g' <<< "${ebuild_name}")" 99 local ebuild_category 100 ebuild_category="$(basename "$(dirname "$(dirname "${ebuild_loc}")")")" 101 local portage_dir='/var/tmp/portage' 102 103 local work_dir="${portage_dir}/${ebuild_category}/${ebuild_name}/work/${package_name}" 104 105 ebuild "${ebuild_loc}" clean 106 USE="${USE_FLAGS}" ebuild "${ebuild_loc}" unpack 107 108 # May need to init git if it doesn't already exist. 109 # Probably could just use git -C instead of the pushd/popd. 110 pushd "${work_dir}" >& /dev/null 111 if [[ ! -d '.git' ]]; then 112 git init 113 git add . 114 git commit -m 'Initial commit' 115 fi 116 popd >& /dev/null 117 118 USE="${USE_FLAGS}" ebuild "${ebuild_loc}" configure 119 120 cp -r -p "${work_dir}/." "${desired_src_loc}" 121 local backup_dir="${work_dir}.bk" 122 mv "${work_dir}" "${backup_dir}" 123 ln -s "$(realpath "${desired_src_loc}")" "${work_dir}" 124 125 pushd "${desired_src_loc}" >& /dev/null 126 127 git add . 128 git commit -m 'Ebuild configure commit' 129 popd >& /dev/null 130 131 echo 132 echo '----------------------------------------' 133 echo 'Successfully created local mirror!' 134 echo "Developer work directory set up at: ${desired_src_loc}" 135 echo 'To build the package, run:' 136 echo " upstream-workon build ${package}" 137 echo 'To install the package, run:' 138 echo " sudo upstream-workon install ${package}" 139 echo "To clean up (without deleting ${desired_src_loc}), run:" 140 echo " upstream-workon clean ${package}" 141 echo "WARNING: Moving original workdir to ${backup_dir}, consider deleting" >&2 142} 143 144clean() { 145 local package="$1" 146 echo 'WARNING: You may need to run this with sudo' >&2 147 local ebuild_loc 148 ebuild_loc="$(resolve_ebuild_for "${package}")" 149 150 ebuild "${ebuild_loc}" clean 151 152 echo '----------------------------------------' 153 echo "Successfully cleaned up ${package}!" 154} 155 156 157compile() { 158 local package="$1" 159 local ebuild_loc 160 ebuild_loc="$(resolve_ebuild_for "${package}")" 161 162 USE="${USE_FLAGS}" ebuild "${ebuild_loc}" compile 163 164 echo '----------------------------------------' 165 echo "Successfully compiled ${package}!" 166} 167 168 169install_src() { 170 local package="$1" 171 echo 'WARNING: You may need to run this with sudo' >&2 172 local ebuild_loc 173 ebuild_loc="$(resolve_ebuild_for "${package}")" 174 175 USE="${USE_FLAGS}" ebuild "${ebuild_loc}" install 176 177 echo '----------------------------------------' 178 echo "Successfully installed ${package}!" 179} 180 181link_src() { 182 local package="$1" 183 local desired_src_loc="$2" 184 local ebuild_loc 185 ebuild_loc="$(resolve_ebuild_for "${package}")" 186 187 local ebuild_name 188 ebuild_name="$(basename "${ebuild_loc}" | sed 's/\.ebuild$//g')" 189 local package_name 190 # shellcheck disable=2001 191 package_name="$(sed 's/-r[0-9]\+$//g' <<< "${ebuild_name}")" 192 local ebuild_category 193 ebuild_category="$(basename "$(dirname "$(dirname "${ebuild_loc}")")")" 194 local portage_dir='/var/tmp/portage' 195 196 local work_dir="${portage_dir}/${ebuild_category}/${ebuild_name}/work/${package_name}" 197 198 local backup_dir="${work_dir}.bk" 199 200 # Because of some annoying permissions issues, we have to configure directly in 201 # /var/tmp/portage/... 202 # We then copy over those changes into our local source directory. 203 # To make sure the proper deletions get done, we delete everything except 204 # your local git directory. 205 206 ebuild "${ebuild_loc}" clean 207 USE="${USE_FLAGS}" ebuild "${ebuild_loc}" configure 208 # TODO(ajordanr): This is a rough edge, and I don't want users to delete their 209 # home directory without knowing what they are doing. So we're copying 210 # everything instead. 211 # TODO(ajordanr): This will ignore git submodules, which I don't want. 212 mv "${desired_src_loc}" "${desired_src_loc}.bk" 213 mkdir "${desired_src_loc}" 214 cp -rP "${desired_src_loc}.bk/.git" "${desired_src_loc}/.git" 215 rsync -a --exclude=".git" "${work_dir}"/* "${desired_src_loc}" 216 rsync -a --exclude=".git" "${work_dir}"/.[^.]* "${desired_src_loc}" 217 mv "${work_dir}" "${backup_dir}" 218 ln -s "$(realpath "${desired_src_loc}")" "${work_dir}" 219 220 echo '----------------------------------------' 221 echo 'Successfully linked to local mirror!' 222 echo "Developer work directory linked to: ${desired_src_loc}" 223 echo "WARNING: Moving original workdir to ${backup_dir}, consider deleting" >&2 224 echo "WARNING: Moving original dev dir to ${desired_src_loc}.bk, consider deleting" >&2 225} 226 227resolve_ebuild_for() { 228 equery w "$1" 229} 230 231CMD="${1:-}" 232 233case "${CMD}" in 234 -h|--help|help) 235 shift 236 echo "${HELP}" 237 print_experimental_warning 238 exit 1 239 ;; 240 init) 241 shift 242 [[ -z "${1:-}" || -z "${2:-}" ]] && incorrect_number_of_arguments 243 print_experimental_warning 244 init "$1" "$2" 245 ;; 246 link) 247 shift 248 [[ -z "${1:-}" || -z "${2:-}" ]] && incorrect_number_of_arguments 249 print_experimental_warning 250 link_src "$1" "$2" 251 ;; 252 build) 253 shift 254 [[ -z "${1:-}" ]] && incorrect_number_of_arguments 255 print_experimental_warning 256 compile "$1" 257 ;; 258 clean) 259 shift 260 [[ -z "${1:-}" ]] && incorrect_number_of_arguments 261 print_experimental_warning 262 clean "$1" 263 ;; 264 install) 265 shift 266 [[ -z "${1:-}" ]] && incorrect_number_of_arguments 267 print_experimental_warning 268 install_src "$1" 269 ;; 270 *) 271 incorrect_number_of_arguments 272 ;; 273esac 274