github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/tools/go_branch.sh (about) 1 #!/bin/bash 2 3 # Copyright 2019 The gVisor Authors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 set -xeou pipefail 18 19 # Remember our current directory. 20 declare orig_dir 21 orig_dir=$(pwd) 22 readonly orig_dir 23 24 # Record the current working commit. 25 declare head 26 head=$(git describe --always) 27 readonly head 28 29 # Create a temporary working directory, and ensure that this directory and all 30 # subdirectories are cleaned up upon exit. 31 declare tmp_dir 32 tmp_dir=$(mktemp -d) 33 readonly tmp_dir 34 finish() { 35 cd "${orig_dir}" # Leave tmp_dir. 36 rm -rf "${tmp_dir}" # Remove all contents. 37 git checkout -f "${head}" # Restore commit. 38 } 39 trap finish EXIT 40 41 # Discover the package name from the go.mod file. 42 declare module origpwd othersrc 43 module=$(cat go.mod | grep -E "^module" | cut -d' ' -f2) 44 origpwd=$(pwd) 45 othersrc=("go.mod" "go.sum" "AUTHORS" "LICENSE") 46 readonly module origpwd othersrc 47 48 # Build an amd64 & arm64 gopath. 49 declare -r go_amd64="${tmp_dir}/amd64" 50 declare -r go_arm64="${tmp_dir}/arm64" 51 make build BAZEL_OPTIONS="" TARGETS="//:gopath" 52 rsync --recursive --delete --copy-links bazel-bin/gopath/ "${go_amd64}" 53 make build BAZEL_OPTIONS=--config=cross-aarch64 TARGETS="//:gopath" 2>/dev/null 54 rsync --recursive --delete --copy-links bazel-bin/gopath/ "${go_arm64}" 55 56 # Strip irrelevant files, i.e. use only arm64 files from the arm64 build. 57 # This is because bazel may generate incorrect files for non-target platforms 58 # as a workaround. See pkg/sentry/loader/vdsodata as an example. 59 find "${go_amd64}/src/${module}" -name '*_arm64*.go' -exec rm -f {} \; 60 find "${go_amd64}/src/${module}" -name '*_arm64*.s' -exec rm -f {} \; 61 find "${go_arm64}/src/${module}" -name '*_amd64*.go' -exec rm -f {} \; 62 find "${go_arm64}/src/${module}" -name '*_amd64*.s' -exec rm -f {} \; 63 64 # See below. The certs.go file is pseudo-random, and therefore will also 65 # differ between the branches. Since we merge, it only has to come from one. 66 # We arbitrarily keep the one from the amd64 branch, and drop the arm64 one. 67 rm -f "${go_arm64}/src/${module}/webhook/pkg/injector/certs.go" 68 69 # Check that all files are compatible. This means that if the files exist in 70 # both architectures, then they must be identical. The only ones that we expect 71 # to exist in a single architecture (due to binary builds) may be different. 72 function cross_check() { 73 (cd "${1}" && find "src/${module}" -type f | \ 74 xargs -n 1 -I {} sh -c "diff '${1}/{}' '${2}/{}' 2>/dev/null; test \$? -ne 1") 75 } 76 cross_check "${go_arm64}" "${go_amd64}" 77 cross_check "${go_amd64}" "${go_arm64}" 78 79 # Merge the two for a complete set of source files. 80 declare -r go_merged="${tmp_dir}/merged" 81 rsync --recursive "${go_amd64}/" "${go_merged}" 82 rsync --recursive "${go_arm64}/" "${go_merged}" 83 84 # We expect to have an existing go branch that we will use as the basis for this 85 # commit. That branch may be empty, but it must exist. We search for this branch 86 # using the local branch, the "origin" branch, and other remotes, in order. 87 git fetch --all 88 declare go_branch 89 go_branch=$( \ 90 git show-ref --hash refs/heads/go || \ 91 git show-ref --hash refs/remotes/origin/go || \ 92 git show-ref --hash go | head -n 1 \ 93 ) 94 readonly go_branch 95 96 # Clone the current repository to the temporary directory, and check out the 97 # current go_branch directory. We move to the new repository for convenience. 98 declare repo_orig 99 repo_orig="$(pwd)" 100 readonly repo_orig 101 declare -r repo_new="${tmp_dir}/repository" 102 git clone . "${repo_new}" 103 cd "${repo_new}" 104 105 # Setup the repository and checkout the branch. 106 git config user.email "gvisor-bot@google.com" 107 git config user.name "gVisor bot" 108 git fetch origin "${go_branch}" 109 git checkout -b go "${go_branch}" 110 111 # Start working on a merge commit that combines the previous history with the 112 # current history. Note that we don't actually want any changes yet. 113 # 114 # N.B. The git behavior changed at some point and the relevant flag was added 115 # to allow for override, so try the only behavior first then pass the flag. 116 git merge --no-commit --strategy ours "${head}" || \ 117 git merge --allow-unrelated-histories --no-commit --strategy ours "${head}" 118 119 # Normalize the permissions on the old branch. Note that they should be 120 # normalized if constructed by this tool, but we do so before the rsync. 121 find . -type f -exec chmod 0644 {} \; 122 find . -type d -exec chmod 0755 {} \; 123 124 # Sync the entire gopath. Note that we exclude auto-generated source files that 125 # will change here. Otherwise, it adds a tremendous amount of noise to commits. 126 # If this file disappears in the future, then presumably we will still delete 127 # the underlying directory. 128 declare -r gopath="${go_merged}/src/${module}" 129 rsync --recursive --delete \ 130 --exclude .git \ 131 --exclude webhook/pkg/injector/certs.go \ 132 "${gopath}/" . 133 134 # Add additional files. 135 for file in "${othersrc[@]}"; do 136 cp "${origpwd}"/"${file}" . 137 done 138 139 # Construct a new README.md. 140 cat > README.md <<EOF 141 # gVisor 142 143 This branch is a synthetic branch, containing only Go sources, that is 144 compatible with standard Go tools. See the master branch for authoritative 145 sources and tests. 146 EOF 147 148 # There are a few solitary files that can get left behind due to the way bazel 149 # constructs the gopath target. Note that we don't find all Go files here 150 # because they may correspond to unused templates, etc. 151 declare -ar binaries=( "runsc" "shim" "webhook" ) 152 for target in "${binaries[@]}"; do 153 mkdir -p "${target}" 154 cp "${repo_orig}/${target}"/*.go "${target}/" 155 done 156 157 # Normalize all permissions. The way bazel constructs the :gopath tree may leave 158 # some strange permissions on files. We don't have anything in this tree that 159 # should be execution, only the Go source files, README.md, and ${othersrc}. 160 find . -type f -exec chmod 0644 {} \; 161 find . -type d -exec chmod 0755 {} \; 162 163 # Update the current working set and commit. 164 # If the current working commit has already been committed to the remote go 165 # branch, then we have nothing to commit here. So allow empty commit. This can 166 # occur when this script is run parallely (via pull_request and push events) 167 # and the push workflow finishes before the pull_request workflow can run this. 168 git add --all && git commit --allow-empty -m "Merge ${head} (automated)" 169 170 # Push the branch back to the original repository. 171 git remote add orig "${repo_orig}" && git push -f orig go:go