xref: /aosp_15_r20/external/toolchain-utils/upstream_workon/upstream_workon.bash (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
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