aboutsummaryrefslogtreecommitdiffstats
path: root/builder-patches.sh
diff options
context:
space:
mode:
Diffstat (limited to 'builder-patches.sh')
-rwxr-xr-xbuilder-patches.sh262
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