1#!/usr/bin/env bash 2USAGE="Publish a new release of a tokio crate 3 4USAGE: 5 $(basename "$0") [OPTIONS] [CRATE] [VERSION] 6 7OPTIONS: 8 -v, --verbose Use verbose Cargo output 9 -d, --dry-run Perform a dry run (do not publish or tag the release) 10 -h, --help Show this help text and exit" 11 12set -euo pipefail 13 14cd "$(dirname "$0")"/.. 15 16DRY_RUN="" 17VERBOSE="" 18 19err() { 20 echo -e "\e[31m\e[1merror:\e[0m" "$@" 1>&2; 21} 22 23status() { 24 WIDTH=12 25 printf "\e[32m\e[1m%${WIDTH}s\e[0m %s\n" "$1" "$2" 26} 27 28verify() { 29 status "Verifying" "if $CRATE v$VERSION can be released" 30 ACTUAL=$(cargo pkgid | sed -n 's/.*#\(.*\)/\1/p') 31 32 if [ "$ACTUAL" != "$VERSION" ]; then 33 err "expected to release version $VERSION, but Cargo.toml contained $ACTUAL" 34 exit 1 35 fi 36 37 if ! cargo --list | grep -q "hack"; then 38 err "missing cargo-hack executable" 39 read -r -p "install it? [Y/n] " INPUT 40 41 case "$INPUT" in 42 [yY][eE][sS]|[yY]) 43 status "Installing" "cargo-hack" 44 cargo install cargo-hack 45 ;; 46 [nN][oO]|[nN]) 47 echo "okay, exiting" 48 exit 1 49 ;; 50 *) 51 err "invalid input $INPUT" 52 exit 1 53 ;; 54 esac 55 fi 56 57 status "Checking" "if $CRATE builds across feature combinations" 58 59 CARGO_HACK=(cargo hack check --feature-powerset --no-dev-deps) 60 61 if [[ "$VERBOSE" ]]; then 62 CARGO_HACK+=("$VERBOSE") 63 fi 64 65 case "$CRATE" in 66 tracing-subscriber) 67 # for tracing-subscriber, don't test a complete powerset because 68 # there are lots of feature flags 69 INCLUDE_FEATURES=(fmt ansi json registry env-filter) 70 "${CARGO_HACK[@]}" --include-features "${INCLUDE_FEATURES[*]}" 71 CARGO_HACK_STATUS="$?" 72 ;; 73 tracing) 74 # checking the full feature powerset for `tracing` will take 75 # *forever* because of the `max_level_XXX` and 76 # `release_max_level_XXX` features 77 EXCLUDE_FEATURES=( 78 max_level_off max_level_error max_level_warn max_level_info 79 max_level_debug max_level_trace release_max_level_off 80 release_max_level_error release_max_level_warn 81 release_max_level_info release_max_level_debug 82 release_max_level_trace 83 ) 84 "${CARGO_HACK[@]}" --exclude-features "${EXCLUDE_FEATURES[*]}" 85 CARGO_HACK_STATUS="$?" 86 ;; 87 *) 88 "${CARGO_HACK[@]}" 89 CARGO_HACK_STATUS="$?" 90 ;; 91 esac 92 93 if [[ "$CARGO_HACK_STATUS" != "0" ]] ; then 94 err "$CRATE did not build with all feature combinations (cargo hack exited with $CARGO_HACK_STATUS)!" 95 exit 1 96 fi 97 98 99 if git tag -l | grep -Fxq "$TAG" ; then 100 err "git tag \`$TAG\` already exists" 101 exit 1 102 fi 103} 104 105release() { 106 status "Releasing" "$CRATE v$VERSION" 107 local CARGO_PACKAGE=(cargo package) 108 local CARGO_PUBLISH=(cargo publish) 109 110 if [[ "$VERBOSE" ]]; then 111 CARGO_PACKAGE+=("$VERBOSE") 112 CARGO_PUBLISH+=("$VERBOSE") 113 fi 114 115 if [[ "$DRY_RUN" ]]; then 116 CARGO_PUBLISH+=("$DRY_RUN") 117 fi 118 119 "${CARGO_PACKAGE[@]}" 120 "${CARGO_PUBLISH[@]}" 121 122 status "Tagging" "$TAG" 123 if [[ "$DRY_RUN" ]]; then 124 echo "# git tag $TAG && git push --tags" 125 else 126 git tag "$TAG" && git push --tags 127 fi 128} 129 130while [[ $# -gt 0 ]] 131do 132 133case "$1" in 134 -v|--verbose) 135 VERBOSE="--verbose" 136 set -x 137 shift 138 ;; 139 -d|--dry-run) 140 DRY_RUN="--dry-run" 141 shift 142 ;; 143 -*) 144 err "unknown flag \"$1\"" 145 echo "$USAGE" 146 exit 1 147 ;; 148 *) # crate or version 149 if [[ -z "${CRATE+crate}" ]]; then 150 CRATE="$1" 151 elif [[ -z "${VERSION+version}" ]]; then 152 VERSION="$1" 153 else 154 err "unknown positional argument \"$1\"" 155 echo "$USAGE" 156 exit 1 157 fi 158 shift 159 ;; 160esac 161done 162# set -- "${POSITIONAL[@]}" 163 164if [[ -z "${VERSION+version}" ]]; then 165 err "no version specified!" 166 HELP=1 167fi 168 169if [[ "${CRATE+crate}" ]]; then 170 TAG="$CRATE-$VERSION" 171else 172 err "no crate specified!" 173 HELP=1 174fi 175 176if [[ "${HELP+help}" ]]; then 177 echo "$USAGE" 178 exit 1 179fi 180 181if [ -d "$CRATE" ]; then 182 (cd "$CRATE" && verify && release ) 183else 184 err "no such crate \"$CRATE\"" 185 exit 1 186fi 187