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