github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/tools/make_apt.sh (about)

     1  #!/bin/bash
     2  
     3  # Copyright 2018 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  if [[ "$#" -le 3 ]]; then
    18    echo "usage: $0 <private-key> <suite> <root> <packages...>"
    19    exit 1
    20  fi
    21  declare private_key
    22  declare suite
    23  declare root
    24  private_key="$(readlink -e "$1")"
    25  suite="$2"
    26  root="$(readlink -m "$3")"
    27  readonly private_key
    28  readonly suite
    29  readonly root
    30  shift; shift; shift # For "$@" below.
    31  
    32  # Ensure that we have the correct packages installed.
    33  function apt_install() {
    34    while true; do
    35      sudo apt-get update &&
    36        sudo apt-get install -y "$@" &&
    37        true
    38      result="${?}"
    39      case $result in
    40        0)
    41          break
    42          ;;
    43        100)
    44          # 100 is the error code that apt-get returns.
    45          ;;
    46        *)
    47          exit $result
    48          ;;
    49      esac
    50    done
    51  }
    52  dpkg-sig --help >/dev/null 2>&1       || apt_install dpkg-sig
    53  apt-ftparchive --help >/dev/null 2>&1 || apt_install apt-utils
    54  xz --help >/dev/null 2>&1             || apt_install xz-utils
    55  
    56  # Verbose from this point.
    57  set -xeo pipefail
    58  
    59  # Create a directory for the release.
    60  declare -r release="${root}/dists/${suite}"
    61  mkdir -p "${release}"
    62  
    63  # Create a temporary keyring, and ensure it is cleaned up.
    64  # Using separate homedir allows us to install apt repositories multiple times
    65  # using the same key. This is a limitation in GnuPG pre-2.1.
    66  declare keyring
    67  declare homedir
    68  declare gpg_opts
    69  keyring="$(mktemp /tmp/keyringXXXXXX.gpg)"
    70  homedir="$(mktemp -d /tmp/homedirXXXXXX)"
    71  gpg_opts=("--no-default-keyring" "--secret-keyring" "${keyring}" "--homedir" "${homedir}")
    72  readonly keyring
    73  readonly homedir
    74  readonly gpg_opts
    75  cleanup() {
    76    rm -rf "${keyring}" "${homedir}"
    77  }
    78  trap cleanup EXIT
    79  
    80  # We attempt the import twice because the first one will fail if the public key
    81  # is not found. This isn't actually a failure for us, because we don't require
    82  # the public key (this may be stored separately). The second import will succeed
    83  # because, in reality, the first import succeeded and it's a no-op.
    84  gpg "${gpg_opts[@]}" --import "${private_key}" || \
    85    gpg "${gpg_opts[@]}" --import "${private_key}"
    86  
    87  # Copy the packages into the root.
    88  for pkg in "$@"; do
    89    if ! [[ -f "${pkg}" ]]; then
    90      continue
    91    fi
    92    ext=${pkg##*.}
    93    if [[ "${ext}" != "deb" ]]; then
    94      continue
    95    fi
    96  
    97    # Extract package information.
    98    name=$(basename "${pkg}" ".${ext}")
    99    arch=$(dpkg --info "${pkg}" | grep 'Architecture:' | cut -d':' -f2)
   100    version=$(dpkg --info "${pkg}" | grep 'Version:' | cut -d':' -f2)
   101    arch=${arch// /} # Trim whitespace.
   102    version=${version// /} # Ditto.
   103    destdir="${root}/pool/${version}/binary-${arch}"
   104  
   105    # Copy & sign the package.
   106    mkdir -p "${destdir}"
   107    cp -a -L "$(dirname "${pkg}")/${name}.deb" "${destdir}"
   108    cp -a -L "$(dirname "${pkg}")/${name}.changes" "${destdir}"
   109    chmod 0644 "${destdir}"/"${name}".*
   110    # Sign a package only if it isn't signed yet.
   111    # We use [*] here to expand the gpg_opts array into a single shell-word.
   112    dpkg-sig -g "${gpg_opts[*]}" --verify "${destdir}/${name}.deb" ||
   113    dpkg-sig -g "${gpg_opts[*]}" --sign builder "${destdir}/${name}.deb"
   114  done
   115  
   116  # Build the package list.
   117  declare arches=()
   118  for dir in "${root}"/pool/*/binary-*; do
   119    name=$(basename "${dir}")
   120    arch=${name##binary-}
   121    arches+=("${arch}")
   122    repo_packages="${release}"/main/"${name}"
   123    mkdir -p "${repo_packages}"
   124    (cd "${root}" && apt-ftparchive packages "${dir##${root}/}" > "${repo_packages}"/Packages)
   125    if ! [[ -s "${repo_packages}"/Packages ]]; then
   126      echo "Packages file is size zero." >&2
   127      exit 1
   128    fi
   129    (cd "${repo_packages}" && cat Packages | gzip > Packages.gz)
   130    (cd "${repo_packages}" && cat Packages | xz > Packages.xz)
   131  done
   132  
   133  # Build the release list.
   134  cat > "${release}"/apt.conf <<EOF
   135  APT {
   136    FTPArchive {
   137      Release {
   138        Architectures "${arches[@]}";
   139        Suite "${suite}";
   140        Components "main";
   141      };
   142    };
   143  };
   144  EOF
   145  (cd "${release}" && apt-ftparchive -c=apt.conf release . > Release)
   146  rm "${release}"/apt.conf
   147  
   148  # Sign the release.
   149  declare -r digest_opts=("--digest-algo" "SHA512" "--cert-digest-algo" "SHA512")
   150  (cd "${release}" && rm -f Release.gpg InRelease)
   151  (cd "${release}" && gpg "${gpg_opts[@]}" --clearsign "${digest_opts[@]}" -o InRelease Release)
   152  (cd "${release}" && gpg "${gpg_opts[@]}" -abs "${digest_opts[@]}" -o Release.gpg Release)