diff options
Diffstat (limited to 'builder-patches.sh')
-rwxr-xr-x | builder-patches.sh | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/builder-patches.sh b/builder-patches.sh new file mode 100755 index 0000000..4934a56 --- /dev/null +++ b/builder-patches.sh @@ -0,0 +1,262 @@ +#!/usr/bin/env sh +# Copyright (C) 2021 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +# During the release process, we need patches in the manifest, in +# vendor/replicant and vendor/replicant-release-scripts to change the +# Replicant revision. + +# When the person who does the release uses a separate computer to +# build Replicant, in some cases, it makes sense to develop the patch +# locally and push them to the remote. + +local_repositories="\ + ../vendor_replicant-release-scripts \ + ../vendor_replicant \ + ../manifest \ +" + +local_tmpdir="$(mktemp -d)" + +usage() +{ + echo "Usage:" + echo "$0 <machine> <replicant_dir> apply" \ + " # Apply patches to the remote git repositories" + echo "$0 <machine> <replicant_dir> remove" \ + "# Remove the last commit from the remote git repositories" + echo "$0 <machine> <replicant_dir> reset" \ + " # run git reset --hard on the remote git repositories" + echo "$0 <machine> <replicant_dir> sync" \ + " # run repo sync on the remote git repositories" + echo "" + echo "Remote repositories:" + for repository in ${local_repositories} ; do + echo "- $(basename ${repository} | sed 's#_#/#g')/" + done + exit 64 # EX_USAGE in sysexits.h +} + +append_raw() +{ + variable="$1" + shift 1 + values="$@" + + if [ -z "$(eval echo \$${variable})" ] ; then + eval "${variable}=\"${values}\"" + else + eval "${variable}=\"\$${variable}${values}\"" + fi +} + +append() +{ + variable="$1" + shift 1 + values="$@" + + if [ -z "$(eval echo \$${variable})" ] ; then + eval "${variable}=\"${values}\"" + else + eval "${variable}=\"\$${variable} ${values}\"" + fi +} + +remote_commands="" +queue_remote_commands() +{ + commands="$@" + + if [ -z "${remote_commands}" ] ; then + append_raw remote_commands "${commands}" + else + append_raw remote_commands ";${commands}" + fi +} + +apply_remote_commands() +{ + machine="$1" + + ssh "${machine}" "${remote_commands}" + remote_commands="" +} + +patches_for_remote="" +queue_patches_for_remote() +{ + patches="$@" + + if [ -z "${patches_for_remote}" ] ; then + append patches_for_remote "${patches}" + else + append patches_for_remote ";${patches}" + fi +} + +send_and_apply_patches_to_remote() +{ + machine="$1" + replicant_dir="$2" + + remote_tmpdir="$(mktemp -d --dry-run)" + + for patch in ${patches_for_remote} ; do + append remote_tmpsubdirs "${remote_tmpdir}/$(dirname ${patch})" + append local_patches_paths "${local_tmpdir}/./${patch}" + queue_remote_commands \ + "cd;cd ${replicant_dir}/$(dirname ${patch} | sed 's#_#/#g')" + # TODO: check if the patch is already applied + queue_remote_commands "git am ${remote_tmpdir}/${patch}" + done + queue_remove_remote_temporary_files "${remote_tmpdir}" + + rsync -Rrav ${local_patches_paths} "${machine}:${remote_tmpdir}/" + apply_remote_commands "${machine}" + patches_for_remote="" +} + +remove_local_temporary_files() +{ + tmpdirs="$@" + + for tmpdir in ${tmpdirs} ; do + for patch in ${patches} ; do + rm -f "${tmpdir}/${patch}" + done + + for repository_dir in ${repositories_dirs} ; do + rmdir "${tmpdir}/${repository_dir}/" + done + + rmdir "${tmpdir}/" + done +} + +queue_remove_remote_temporary_files() +{ + tmpdirs="$@" + + for tmpdir in ${tmpdirs} ; do + for patch in ${patches} ; do + queue_remote_commands "rm -f ${tmpdir}/${patch}" + done + + for repository_dir in ${repositories_dirs} ; do + queue_remote_commands \ + "rmdir ${tmpdir}/${repository_dir}/" + done + + queue_remote_commands "rmdir ${tmpdir}/" + done +} + +apply_patches_to_remote() +{ + machine="$1" + replicant_dir="$2" + + patches="" + repositories_dirs="" + + for repository in ${local_repositories} ; do + patch="$(git -C ${repository} format-patch -1)" + destdir="${local_tmpdir}/$(basename ${repository})" + + mkdir -p "${destdir}/" + mv -f "${repository}/${patch}" "${destdir}/" + + append "patches" "$(basename ${repository})/${patch}" + append "repositories_dirs" "$(basename ${repository})" + done + + queue_patches_for_remote "${patches}" + send_and_apply_patches_to_remote "${machine}" "${replicant_dir}" + + remove_local_temporary_files "${local_tmpdir}" +} + +apply_git_reset_hard_to_remote() +{ + machine="$1" + replicant_dir="$2" + + patches="" + repositories_dirs="" + + for repository in ${local_repositories} ; do + remote_git_dir="$(echo $(basename ${repository}) \ + | sed 's#_#/#g')" + queue_remote_commands "cd;cd ${replicant_dir}" + queue_remote_commands "git -C ${remote_git_dir} reset --hard" + done + apply_remote_commands "${machine}" +} + +remove_top_patches_from_remote() +{ + machine="$1" + replicant_dir="$2" + + for repository in ${local_repositories} ; do + remote_git_dir="$(echo $(basename ${repository}) \ + | sed 's#_#/#g')" + queue_remote_commands "cd;cd ${replicant_dir}" + queue_remote_commands \ + "GIT_EDITOR='echo noop > ' \ + git -C ${remote_git_dir} rebase -i HEAD~1" + done + apply_remote_commands "${machine}" +} + +repo_sync_remote_repositories() +{ + machine="$1" + replicant_dir="$2" + + for repository in ${local_repositories} ; do + append \ + "remote_repositories_paths" \ + "$(echo $(basename ${repository})| sed 's#_#/#g')" + done + + queue_remote_commands "cd;cd ${replicant_dir}" + # When using repo sync, repo update itself automatically. But + # the updated repo doesn't work anymore withTrisquel 9 python3 + # version.To workaround that issue, Replicant released a + # tarball (built with Guix) that includes a newer repo and all + # its dependencies (including python). And to work properly we + # need to source a script that setups the environment + # variables to make that repo work. + queue_remote_commands \ + "[ -f /usr/local/bin/repo-env.sh ] && \ + source /usr/local/bin/repo-env.sh" + queue_remote_commands "repo sync ${remote_repositories_paths}" + + apply_remote_commands "${machine}" +} + +if [ $# -ne 3 ] ; then + usage +elif [ "$3" = "apply" ] ; then + apply_patches_to_remote "$1" "$2" +elif [ "$3" = "remove" ] ; then + remove_top_patches_from_remote "$1" "$2" +elif [ "$3" = "reset" ] ; then + apply_git_reset_hard_to_remote "$1" "$2" +elif [ "$3" = "sync" ] ; then + repo_sync_remote_repositories "$1" "$2" +fi |