1 #!/usr/bin/env bash 2 # Copyright 2017 The TensorFlow Authors. All Rights Reserved. 3 # 4 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # you may not use this file except in compliance with the License. 6 # You may obtain a copy of the License at 7 # 8 # http://www.apache.org/licenses/LICENSE-2.0 9 # 10 # Unless required by applicable law or agreed to in writing, software 11 # distributed under the License is distributed on an "AS IS" BASIS, 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 # See the License for the specific language governing permissions and 14 # limitations under the License. 15 # ============================================================================== 16 # 17 # This script is intended to be run inside a docker container to provide a 18 # hermetic process. See release.sh for the expected invocation. 19 20 21 RELEASE_URL_PREFIX="https://storage.googleapis.com/tensorflow/libtensorflow" 22 23 # By default we deploy to both ossrh and bintray. These two 24 # environment variables can be set to skip either repository. 25 DEPLOY_BINTRAY="${DEPLOY_BINTRAY:-true}" 26 DEPLOY_OSSRH="${DEPLOY_OSSRH:-true}" 27 28 IS_SNAPSHOT="false" 29 if [[ "${TF_VERSION}" == *"-SNAPSHOT" ]]; then 30 IS_SNAPSHOT="true" 31 # Bintray does not allow snapshots. 32 DEPLOY_BINTRAY="false" 33 fi 34 PROTOC_RELEASE_URL="https://github.com/google/protobuf/releases/download/v3.3.0/protoc-3.3.0-linux-x86_64.zip" 35 if [[ "${DEPLOY_BINTRAY}" != "true" && "${DEPLOY_OSSRH}" != "true" ]]; then 36 echo "Must deploy to at least one of Bintray or OSSRH" >&2 37 exit 2 38 fi 39 40 set -ex 41 42 clean() { 43 # Clean up any existing artifacts 44 # (though if run inside a clean docker container, there won't be any dirty 45 # artifacts lying around) 46 mvn -q clean 47 rm -rf libtensorflow_jni/src libtensorflow_jni/target libtensorflow_jni_gpu/src libtensorflow_jni_gpu/target libtensorflow/src libtensorflow/target tensorflow-android/target 48 } 49 50 update_version_in_pom() { 51 mvn versions:set -DnewVersion="${TF_VERSION}" 52 } 53 54 # Fetch a property from pom files for a given profile. 55 # Arguments: 56 # profile - name of the selected profile. 57 # property - name of the property to be retrieved. 58 # Output: 59 # Echo property value to stdout 60 mvn_property() { 61 local profile="$1" 62 local prop="$2" 63 mvn -q --non-recursive exec:exec -P "${profile}" \ 64 -Dexec.executable='echo' \ 65 -Dexec.args="\${${prop}}" 66 } 67 68 download_libtensorflow() { 69 if [[ "${IS_SNAPSHOT}" == "true" ]]; then 70 URL="http://ci.tensorflow.org/view/Nightly/job/nightly-libtensorflow/TYPE=cpu-slave/lastSuccessfulBuild/artifact/lib_package/libtensorflow-src.jar" 71 else 72 URL="${RELEASE_URL_PREFIX}/libtensorflow-src-${TF_VERSION}.jar" 73 fi 74 curl -L "${URL}" -o /tmp/src.jar 75 cd "${DIR}/libtensorflow" 76 jar -xvf /tmp/src.jar 77 rm -rf META-INF 78 cd "${DIR}" 79 } 80 81 # Fetch the android aar artifact from the CI build system, and update 82 # its associated pom file. 83 update_tensorflow_android() { 84 TARGET_DIR="${DIR}/tensorflow-android/target" 85 mkdir -p "${TARGET_DIR}" 86 python "${DIR}/tensorflow-android/update.py" \ 87 --version "${TF_VERSION}" \ 88 --template "${DIR}/tensorflow-android/pom-android.xml.template" \ 89 --dir "${TARGET_DIR}" 90 } 91 92 download_libtensorflow_jni() { 93 NATIVE_DIR="${DIR}/libtensorflow_jni/src/main/resources/org/tensorflow/native" 94 mkdir -p "${NATIVE_DIR}" 95 cd "${NATIVE_DIR}" 96 97 mkdir linux-x86_64 98 mkdir windows-x86_64 99 mkdir darwin-x86_64 100 101 if [[ "${IS_SNAPSHOT}" == "true" ]]; then 102 # Nightly builds from http://ci.tensorflow.org/view/Nightly/job/nightly-libtensorflow/ 103 # and http://ci.tensorflow.org/view/Nightly/job/nightly-libtensorflow-windows/ 104 curl -L "http://ci.tensorflow.org/view/Nightly/job/nightly-libtensorflow/TYPE=cpu-slave/lastSuccessfulBuild/artifact/lib_package/libtensorflow_jni-cpu-linux-x86_64.tar.gz" | tar -xvz -C linux-x86_64 105 curl -L "http://ci.tensorflow.org/view/Nightly/job/nightly-libtensorflow/TYPE=mac-slave/lastSuccessfulBuild/artifact/lib_package/libtensorflow_jni-cpu-darwin-x86_64.tar.gz" | tar -xvz -C darwin-x86_64 106 curl -L "http://ci.tensorflow.org/view/Nightly/job/nightly-libtensorflow-windows/lastSuccessfulBuild/artifact/lib_package/libtensorflow_jni-cpu-windows-x86_64.zip" -o /tmp/windows.zip 107 else 108 curl -L "${RELEASE_URL_PREFIX}/libtensorflow_jni-cpu-linux-x86_64-${TF_VERSION}.tar.gz" | tar -xvz -C linux-x86_64 109 curl -L "${RELEASE_URL_PREFIX}/libtensorflow_jni-cpu-darwin-x86_64-${TF_VERSION}.tar.gz" | tar -xvz -C darwin-x86_64 110 curl -L "${RELEASE_URL_PREFIX}/libtensorflow_jni-cpu-windows-x86_64-${TF_VERSION}.zip" -o /tmp/windows.zip 111 fi 112 113 unzip /tmp/windows.zip -d windows-x86_64 114 rm -f /tmp/windows.zip 115 # Updated timestamps seem to be required to get Maven to pick up the file. 116 touch linux-x86_64/* 117 touch darwin-x86_64/* 118 touch windows-x86_64/* 119 cd "${DIR}" 120 } 121 122 download_libtensorflow_jni_gpu() { 123 NATIVE_DIR="${DIR}/libtensorflow_jni_gpu/src/main/resources/org/tensorflow/native" 124 mkdir -p "${NATIVE_DIR}" 125 cd "${NATIVE_DIR}" 126 127 mkdir linux-x86_64 128 129 if [[ "${IS_SNAPSHOT}" == "true" ]]; then 130 # Nightly builds from http://ci.tensorflow.org/view/Nightly/job/nightly-libtensorflow/ 131 # and http://ci.tensorflow.org/view/Nightly/job/nightly-libtensorflow-windows/ 132 curl -L "http://ci.tensorflow.org/view/Nightly/job/nightly-libtensorflow/TYPE=gpu-linux/lastSuccessfulBuild/artifact/lib_package/libtensorflow_jni-gpu-linux-x86_64.tar.gz" | tar -xvz -C linux-x86_64 133 else 134 curl -L "${RELEASE_URL_PREFIX}/libtensorflow_jni-gpu-linux-x86_64-${TF_VERSION}.tar.gz" | tar -xvz -C linux-x86_64 135 fi 136 137 # Updated timestamps seem to be required to get Maven to pick up the file. 138 touch linux-x86_64/* 139 cd "${DIR}" 140 } 141 142 # Ideally, the .jar for generated Java code for TensorFlow protocol buffer files 143 # would have been produced by bazel rules. However, protocol buffer library 144 # support in bazel is in flux. Once 145 # https://github.com/bazelbuild/bazel/issues/2626 has been resolved, perhaps 146 # TensorFlow can move to something like 147 # https://bazel.build/blog/2017/02/27/protocol-buffers.html 148 # for generating C++, Java and Python code for protocol buffers. 149 # 150 # At that point, perhaps the libtensorflow build scripts 151 # (tensorflow/tools/ci_build/builds/libtensorflow.sh) can build .jars for 152 # generated code and this function would not need to download protoc to generate 153 # code. 154 generate_java_protos() { 155 # Clean any previous attempts 156 rm -rf "${DIR}/proto/tmp" 157 158 # Download protoc 159 curl -L "${PROTOC_RELEASE_URL}" -o "/tmp/protoc.zip" 160 mkdir -p "${DIR}/proto/tmp/protoc" 161 unzip -d "${DIR}/proto/tmp/protoc" "/tmp/protoc.zip" 162 rm -f "/tmp/protoc.zip" 163 164 # Download the release archive of TensorFlow protos. 165 if [[ "${IS_SNAPSHOT}" == "true" ]]; then 166 URL="http://ci.tensorflow.org/view/Nightly/job/nightly-libtensorflow/TYPE=cpu-slave/lastSuccessfulBuild/artifact/lib_package/libtensorflow_proto.zip" 167 else 168 URL="${RELEASE_URL_PREFIX}/libtensorflow_proto-${TF_VERSION}.zip" 169 fi 170 curl -L "${URL}" -o /tmp/libtensorflow_proto.zip 171 mkdir -p "${DIR}/proto/tmp/src" 172 unzip -d "${DIR}/proto/tmp/src" "/tmp/libtensorflow_proto.zip" 173 rm -f "/tmp/libtensorflow_proto.zip" 174 175 # Generate Java code 176 mkdir -p "${DIR}/proto/src/main/java" 177 find "${DIR}/proto/tmp/src" -name "*.proto" | xargs \ 178 ${DIR}/proto/tmp/protoc/bin/protoc \ 179 --proto_path="${DIR}/proto/tmp/src" \ 180 --java_out="${DIR}/proto/src/main/java" 181 182 # Cleanup 183 rm -rf "${DIR}/proto/tmp" 184 } 185 186 # Deploy artifacts using a specific profile. 187 # Arguments: 188 # profile - name of selected profile. 189 # Outputs: 190 # n/a 191 deploy_profile() { 192 local profile="$1" 193 # Deploy the non-android pieces. 194 mvn deploy -P"${profile}" 195 # Determine the correct pom file property to use 196 # for the repository url. 197 local rtype 198 if [[ "${IS_SNAPSHOT}" == "true" ]]; then 199 rtype='snapshotRepository' 200 else 201 rtype='repository' 202 fi 203 local url=$(mvn_property "${profile}" "project.distributionManagement.${rtype}.url") 204 local repositoryId=$(mvn_property "${profile}" "project.distributionManagement.${rtype}.id") 205 mvn gpg:sign-and-deploy-file \ 206 -Dfile="${DIR}/tensorflow-android/target/tensorflow.aar" \ 207 -DpomFile="${DIR}/tensorflow-android/target/pom-android.xml" \ 208 -Durl="${url}" \ 209 -DrepositoryId="${repositoryId}" 210 } 211 212 # If successfully built, try to deploy. 213 # If successfully deployed, clean. 214 # If deployment fails, debug with 215 # ./release.sh ${TF_VERSION} ${SETTINGS_XML} bash 216 # To get a shell to poke around the maven artifacts with. 217 deploy_artifacts() { 218 # Deploy artifacts to ossrh if requested. 219 if [[ "${DEPLOY_OSSRH}" == "true" ]]; then 220 deploy_profile 'ossrh' 221 fi 222 # Deploy artifacts to bintray if requested. 223 if [[ "${DEPLOY_BINTRAY}" == "true" ]]; then 224 deploy_profile 'bintray' 225 fi 226 # Clean up when everything works 227 clean 228 } 229 230 if [ -z "${TF_VERSION}" ] 231 then 232 echo "Must set the TF_VERSION environment variable" 233 exit 1 234 fi 235 236 DIR="$(realpath $(dirname $0))" 237 cd "${DIR}" 238 239 # The meat of the script. 240 # Comment lines out appropriately if debugging/tinkering with the release 241 # process. 242 # gnupg2 is required for signing 243 apt-get -qq update && apt-get -qqq install -y gnupg2 244 clean 245 update_version_in_pom 246 download_libtensorflow 247 download_libtensorflow_jni 248 download_libtensorflow_jni_gpu 249 update_tensorflow_android 250 generate_java_protos 251 # Build the release artifacts 252 mvn verify 253 # Push artifacts to repository 254 deploy_artifacts 255 256 set +ex 257 if [[ "${IS_SNAPSHOT}" == "false" ]]; then 258 echo "Uploaded to the staging repository" 259 echo "After validating the release: " 260 if [[ "${DEPLOY_OSSRH}" == "true" ]]; then 261 echo "* Login to https://oss.sonatype.org/#stagingRepositories" 262 echo "* Find the 'org.tensorflow' staging release and click either 'Release' to release or 'Drop' to abort" 263 fi 264 if [[ "${DEPLOY_BINTRAY}" == "true" ]]; then 265 echo "* Login to https://bintray.com/google/tensorflow/tensorflow" 266 echo "* Either 'Publish' unpublished items to release, or 'Discard' to abort" 267 fi 268 else 269 echo "Uploaded to the snapshot repository" 270 fi 271