172 lines
6.6 KiB
Bash
Executable File
172 lines
6.6 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Copyright 2019 The gVisor Authors.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
set -xeou pipefail
|
|
|
|
# Remember our current directory.
|
|
declare orig_dir
|
|
orig_dir=$(pwd)
|
|
readonly orig_dir
|
|
|
|
# Record the current working commit.
|
|
declare head
|
|
head=$(git describe --always)
|
|
readonly head
|
|
|
|
# Create a temporary working directory, and ensure that this directory and all
|
|
# subdirectories are cleaned up upon exit.
|
|
declare tmp_dir
|
|
tmp_dir=$(mktemp -d)
|
|
readonly tmp_dir
|
|
finish() {
|
|
cd "${orig_dir}" # Leave tmp_dir.
|
|
rm -rf "${tmp_dir}" # Remove all contents.
|
|
git checkout -f "${head}" # Restore commit.
|
|
}
|
|
trap finish EXIT
|
|
|
|
# Discover the package name from the go.mod file.
|
|
declare module origpwd othersrc
|
|
module=$(cat go.mod | grep -E "^module" | cut -d' ' -f2)
|
|
origpwd=$(pwd)
|
|
othersrc=("go.mod" "go.sum" "AUTHORS" "LICENSE")
|
|
readonly module origpwd othersrc
|
|
|
|
# Build an amd64 & arm64 gopath.
|
|
declare -r go_amd64="${tmp_dir}/amd64"
|
|
declare -r go_arm64="${tmp_dir}/arm64"
|
|
make build BAZEL_OPTIONS="" TARGETS="//:gopath"
|
|
rsync --recursive --delete --copy-links bazel-bin/gopath/ "${go_amd64}"
|
|
make build BAZEL_OPTIONS=--config=cross-aarch64 TARGETS="//:gopath" 2>/dev/null
|
|
rsync --recursive --delete --copy-links bazel-bin/gopath/ "${go_arm64}"
|
|
|
|
# Strip irrelevant files, i.e. use only arm64 files from the arm64 build.
|
|
# This is because bazel may generate incorrect files for non-target platforms
|
|
# as a workaround. See pkg/sentry/loader/vdsodata as an example.
|
|
find "${go_amd64}/src/${module}" -name '*_arm64*.go' -exec rm -f {} \;
|
|
find "${go_amd64}/src/${module}" -name '*_arm64*.s' -exec rm -f {} \;
|
|
find "${go_arm64}/src/${module}" -name '*_amd64*.go' -exec rm -f {} \;
|
|
find "${go_arm64}/src/${module}" -name '*_amd64*.s' -exec rm -f {} \;
|
|
|
|
# See below. The certs.go file is pseudo-random, and therefore will also
|
|
# differ between the branches. Since we merge, it only has to come from one.
|
|
# We arbitrarily keep the one from the amd64 branch, and drop the arm64 one.
|
|
rm -f "${go_arm64}/src/${module}/webhook/pkg/injector/certs.go"
|
|
|
|
# Check that all files are compatible. This means that if the files exist in
|
|
# both architectures, then they must be identical. The only ones that we expect
|
|
# to exist in a single architecture (due to binary builds) may be different.
|
|
function cross_check() {
|
|
(cd "${1}" && find "src/${module}" -type f | \
|
|
xargs -n 1 -I {} sh -c "diff '${1}/{}' '${2}/{}' 2>/dev/null; test \$? -ne 1")
|
|
}
|
|
cross_check "${go_arm64}" "${go_amd64}"
|
|
cross_check "${go_amd64}" "${go_arm64}"
|
|
|
|
# Merge the two for a complete set of source files.
|
|
declare -r go_merged="${tmp_dir}/merged"
|
|
rsync --recursive "${go_amd64}/" "${go_merged}"
|
|
rsync --recursive "${go_arm64}/" "${go_merged}"
|
|
|
|
# We expect to have an existing go branch that we will use as the basis for this
|
|
# commit. That branch may be empty, but it must exist. We search for this branch
|
|
# using the local branch, the "origin" branch, and other remotes, in order.
|
|
git fetch --all
|
|
declare go_branch
|
|
go_branch=$( \
|
|
git show-ref --hash refs/heads/go || \
|
|
git show-ref --hash refs/remotes/origin/go || \
|
|
git show-ref --hash go | head -n 1 \
|
|
)
|
|
readonly go_branch
|
|
|
|
# Clone the current repository to the temporary directory, and check out the
|
|
# current go_branch directory. We move to the new repository for convenience.
|
|
declare repo_orig
|
|
repo_orig="$(pwd)"
|
|
readonly repo_orig
|
|
declare -r repo_new="${tmp_dir}/repository"
|
|
git clone . "${repo_new}"
|
|
cd "${repo_new}"
|
|
|
|
# Setup the repository and checkout the branch.
|
|
git config user.email "gvisor-bot@google.com"
|
|
git config user.name "gVisor bot"
|
|
git fetch origin "${go_branch}"
|
|
git checkout -b go "${go_branch}"
|
|
|
|
# Start working on a merge commit that combines the previous history with the
|
|
# current history. Note that we don't actually want any changes yet.
|
|
#
|
|
# N.B. The git behavior changed at some point and the relevant flag was added
|
|
# to allow for override, so try the only behavior first then pass the flag.
|
|
git merge --no-commit --strategy ours "${head}" || \
|
|
git merge --allow-unrelated-histories --no-commit --strategy ours "${head}"
|
|
|
|
# Normalize the permissions on the old branch. Note that they should be
|
|
# normalized if constructed by this tool, but we do so before the rsync.
|
|
find . -type f -exec chmod 0644 {} \;
|
|
find . -type d -exec chmod 0755 {} \;
|
|
|
|
# Sync the entire gopath. Note that we exclude auto-generated source files that
|
|
# will change here. Otherwise, it adds a tremendous amount of noise to commits.
|
|
# If this file disappears in the future, then presumably we will still delete
|
|
# the underlying directory.
|
|
declare -r gopath="${go_merged}/src/${module}"
|
|
rsync --recursive --delete \
|
|
--exclude .git \
|
|
--exclude webhook/pkg/injector/certs.go \
|
|
"${gopath}/" .
|
|
|
|
# Add additional files.
|
|
for file in "${othersrc[@]}"; do
|
|
cp "${origpwd}"/"${file}" .
|
|
done
|
|
|
|
# Construct a new README.md.
|
|
cat > README.md <<EOF
|
|
# gVisor
|
|
|
|
This branch is a synthetic branch, containing only Go sources, that is
|
|
compatible with standard Go tools. See the master branch for authoritative
|
|
sources and tests.
|
|
EOF
|
|
|
|
# There are a few solitary files that can get left behind due to the way bazel
|
|
# constructs the gopath target. Note that we don't find all Go files here
|
|
# because they may correspond to unused templates, etc.
|
|
declare -ar binaries=( "runsc" "shim" "webhook" )
|
|
for target in "${binaries[@]}"; do
|
|
mkdir -p "${target}"
|
|
cp "${repo_orig}/${target}"/*.go "${target}/"
|
|
done
|
|
|
|
# Normalize all permissions. The way bazel constructs the :gopath tree may leave
|
|
# some strange permissions on files. We don't have anything in this tree that
|
|
# should be execution, only the Go source files, README.md, and ${othersrc}.
|
|
find . -type f -exec chmod 0644 {} \;
|
|
find . -type d -exec chmod 0755 {} \;
|
|
|
|
# Update the current working set and commit.
|
|
# If the current working commit has already been committed to the remote go
|
|
# branch, then we have nothing to commit here. So allow empty commit. This can
|
|
# occur when this script is run parallely (via pull_request and push events)
|
|
# and the push workflow finishes before the pull_request workflow can run this.
|
|
git add --all && git commit --allow-empty -m "Merge ${head} (automated)"
|
|
|
|
# Push the branch back to the original repository.
|
|
git remote add orig "${repo_orig}" && git push -f orig go:go
|