Junxiao Shi | 48ada89 | 2021-11-04 09:02:21 -0600 | [diff] [blame] | 1 | # -*- Mode:bash; c-file-style:"gnu"; indent-tabs-mode:nil -*- */ |
| 2 | # |
| 3 | # Copyright (C) 2015-2021, The University of Memphis, |
| 4 | # Arizona Board of Regents, |
| 5 | # Regents of the University of California. |
| 6 | # |
| 7 | # This file is part of Mini-NDN. |
| 8 | # See AUTHORS.md for a complete list of Mini-NDN authors and contributors. |
| 9 | # |
| 10 | # Mini-NDN is free software: you can redistribute it and/or modify |
| 11 | # it under the terms of the GNU General Public License as published by |
| 12 | # the Free Software Foundation, either version 3 of the License, or |
| 13 | # (at your option) any later version. |
| 14 | # |
| 15 | # Mini-NDN is distributed in the hope that it will be useful, |
| 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | # GNU General Public License for more details. |
| 19 | # |
| 20 | # You should have received a copy of the GNU General Public License |
| 21 | # along with Mini-NDN, e.g., in COPYING.md file. |
| 22 | # If not, see <http://www.gnu.org/licenses/>. |
| 23 | |
| 24 | # needed by Python version detection logic in Mininet & Mininet-WiFi install script |
| 25 | export PYTHON=python3 |
| 26 | |
| 27 | # DEP_INFO key should match *_VERSION variable name. |
| 28 | # DEP_INFO entry should have these comma separated fields: |
| 29 | # [0] local directory name |
| 30 | # [1] dep name |
| 31 | # [2] PPA package name |
| 32 | # [3] GitHub repository (HTTPS) |
| 33 | # [4] Gerrit repository (repo name only) |
| 34 | declare -A DEP_INFO |
| 35 | DEP_INFO=( |
| 36 | ["CXX"]="ndn-cxx,ndn-cxx,libndn-cxx-dev,https://github.com/named-data/ndn-cxx.git,ndn-cxx" |
| 37 | ["NFD"]="NFD,NFD,nfd,https://github.com/named-data/NFD.git,NFD" |
| 38 | ["PSYNC"]="PSync,PSync,libpsync-dev,https://github.com/named-data/PSync.git,PSync" |
| 39 | ["NLSR"]="NLSR,NLSR,nlsr,https://github.com/named-data/NLSR.git,NLSR" |
| 40 | ["TOOLS"]="ndn-tools,NDN Essential Tools,ndn-tools,https://github.com/named-data/ndn-tools.git,ndn-tools" |
| 41 | ["TRAFFIC"]="ndn-traffic-generator,NDN Traffic Generator,ndn-traffic-generator,https://github.com/named-data/ndn-traffic-generator.git,ndn-traffic-generator" |
| 42 | ["INFOEDIT"]="infoedit,infoedit,,https://github.com/NDN-Routing/infoedit.git," |
| 43 | ["MININET"]="mininet,Mininet,,https://github.com/mininet/mininet.git," |
| 44 | ["MNWIFI"]="mininet-wifi,Mininet-WiFi,,https://github.com/intrig-unicamp/mininet-wifi.git," |
| 45 | ) |
| 46 | |
| 47 | # command to detect dependency existence |
| 48 | # if not specified, dependency is assumed to not exist |
| 49 | declare -A DEP_DETECT |
| 50 | DEP_DETECT=( |
| 51 | ["CXX"]="pkg-config libndn-cxx" |
| 52 | ["NFD"]="command -v nfd" |
| 53 | ["PSYNC"]="pkg-config PSync" |
| 54 | ["NLSR"]="command -v nlsr" |
| 55 | ["TOOLS"]="command -v ndnping && command -v ndncatchunks" |
| 56 | ["TRAFFIC"]="command -v ndn-traffic-client" |
| 57 | ["INFOEDIT"]="command -v infoedit" |
| 58 | ["MININET"]="command -v mn && command -v ofdatapath && $PYTHON -m pip show mininet" |
| 59 | ["MNWIFI"]="$PYTHON -m pip show mininet-wifi" |
| 60 | ) |
| 61 | |
| 62 | # non-Waf build & install command |
| 63 | build_INFOEDIT() { |
| 64 | make -j${NJOBS} |
| 65 | $SUDO make install |
| 66 | } |
| 67 | build_MININET() { |
| 68 | ./util/install.sh -s ${CODEROOT} -nv |
| 69 | if ! command -v ofdatapath >/dev/null; then |
| 70 | rm -rf ${CODEROOT}/openflow |
| 71 | ./util/install.sh -s ${CODEROOT} -f |
| 72 | fi |
| 73 | |
| 74 | $SUDO $PYTHON setup.py develop |
| 75 | $SUDO cp /usr/local/bin/mn /usr/local/bin/mn.mininet |
| 76 | } |
| 77 | build_MNWIFI() { |
| 78 | # issue: util/install.sh attempts to patch hostap every time, causing "Assume -R?" prompt |
| 79 | # during reinstalls |
| 80 | # workaround: revert hostap repository to clean state |
| 81 | $SUDO git -C hostap clean -fdx || true |
| 82 | $SUDO git -C hostap checkout -- . || true |
| 83 | |
| 84 | # issue: util/install.sh is not using 'sudo' where needed |
| 85 | # solution: run whole script in 'sudo' |
| 86 | $SUDO env PYTHON="$PYTHON" ./util/install.sh -Wl |
| 87 | |
| 88 | # issue: setup.py reports "Cannot load backend 'TkAgg' which requires the 'tk' interactive |
| 89 | # framework, as 'headless' is currently running" when running over SSH |
| 90 | # workaround: pretend to have X11 display |
| 91 | $SUDO env DISPLAY=:0 $PYTHON setup.py develop |
| 92 | $SUDO cp /usr/local/bin/mn /usr/local/bin/mn.wifi |
| 93 | |
| 94 | # make 'mn' command refer to Mininet's version, which does not require X11 |
| 95 | if [[ -x /usr/local/bin/mn.mininet ]]; then |
| 96 | $SUDO cp /usr/local/bin/mn.mininet /usr/local/bin/mn |
| 97 | fi |
| 98 | } |
| 99 | |
| 100 | # Waf configure options |
| 101 | declare -A DEP_WAFOPTS |
| 102 | DEP_WAFOPTS=( |
| 103 | ["NFD"]="--without-websocket" |
| 104 | ["PSYNC"]="--with-examples" |
| 105 | ) |
| 106 | |
| 107 | # return whether dep is installed |
| 108 | dep_exists() { |
| 109 | if [[ $IGNORE_EXISTING -eq 1 ]]; then |
| 110 | return 2 |
| 111 | fi |
| 112 | local DETECT="${DEP_DETECT[$1]}" |
| 113 | if [[ -n $DETECT ]] && bash -c "$DETECT" &>/dev/null; then |
| 114 | return 0 |
| 115 | fi |
| 116 | return 1 |
| 117 | } |
| 118 | |
| 119 | # set to 1 if dep needs downloading |
| 120 | declare -A NEED_DL |
| 121 | |
| 122 | # display prompt on what to do with dep, populate NEED_DL |
| 123 | dep_prompt() { |
| 124 | local INFO=() |
| 125 | IFS=',' read -a INFO <<< "${DEP_INFO[$1]}" |
| 126 | local VERSION_VAR="$1_VERSION" |
| 127 | local VERSION="${!VERSION_VAR}" |
| 128 | if [[ -z $VERSION ]]; then |
| 129 | VERSION='(default branch)' |
| 130 | fi |
| 131 | local DLDIR="${CODEROOT}/${INFO[0]}" |
| 132 | if dep_exists $1; then |
| 133 | echo "Will use existing ${INFO[1]}" |
| 134 | elif [[ $PREFER_FROM == ppa ]] && [[ -n ${INFO[2]} ]]; then |
| 135 | echo "Will install ${INFO[1]} from named-data PPA" |
| 136 | PPA_PKGS+=("${INFO[2]}") |
| 137 | elif [[ -d "$DLDIR" ]]; then |
| 138 | if [[ $DL_ONLY -ne 1 ]]; then |
| 139 | echo "Will install ${INFO[1]} from local checkout ${DLDIR}" |
| 140 | fi |
| 141 | else |
| 142 | NEED_DL[$1]=1 |
| 143 | if [[ $DL_ONLY -eq 1 ]]; then |
| 144 | echo "Will checkout ${INFO[1]} ${VERSION} to ${DLDIR}" |
| 145 | else |
| 146 | echo "Will download and install ${INFO[1]} ${VERSION}" |
| 147 | fi |
| 148 | fi |
| 149 | } |
| 150 | |
| 151 | # download dep source code |
| 152 | dep_checkout() { |
| 153 | if [[ ${NEED_DL[$1]} -ne 1 ]]; then |
| 154 | return |
| 155 | fi |
| 156 | local INFO=() |
| 157 | IFS=',' read -a INFO <<< "${DEP_INFO[$1]}" |
| 158 | local VERSION_VAR="$1_VERSION" |
| 159 | local VERSION="${!VERSION_VAR}" |
| 160 | local DLDIR="${CODEROOT}/${INFO[0]}" |
| 161 | |
| 162 | if [[ -n ${INFO[4]} ]] && [[ "$VERSION" =~ ^[0-9]+,[0-9]+$ ]]; then |
| 163 | local REPO="https://gerrit.named-data.net/${INFO[4]}" |
| 164 | local GERRIT_CHANGE=${VERSION%,*} |
| 165 | local GERRIT_PATCHSET=${VERSION#*,} |
| 166 | echo "Downloading ${INFO[2]} from Gerrit (patchset ${GERRIT_CHANGE},${GERRIT_PATCHSET})" |
| 167 | git clone "$REPO" "$DLDIR" |
| 168 | git -C "$DLDIR" fetch origin "refs/changes/${GERRIT_CHANGE:(-2)}/${GERRIT_CHANGE}/${GERRIT_PATCHSET}" |
| 169 | git -C "$DLDIR" -c advice.detachedHead=false checkout FETCH_HEAD |
| 170 | elif [[ -z $VERSION ]]; then |
| 171 | echo "Downloading ${INFO[1]} from GitHub (default branch)" |
| 172 | git clone "${INFO[3]}" "$DLDIR" |
| 173 | elif [[ "$VERSION" =~ @ ]]; then |
| 174 | local REPO=${VERSION%@*} |
| 175 | local BRANCH=${VERSION#*@} |
| 176 | echo "Downloading ${INFO[1]} from ${REPO} (branch ${BRANCH})" |
| 177 | git clone "$REPO" "$DLDIR" |
| 178 | git -C "$DLDIR" -c advice.detachedHead=false checkout "$BRANCH" |
| 179 | else |
| 180 | echo "Downloading ${INFO[1]} from GitHub (branch ${VERSION})" |
| 181 | git clone "${INFO[3]}" "$DLDIR" |
| 182 | git -C "$DLDIR" -c advice.detachedHead=false checkout "$VERSION" |
| 183 | fi |
| 184 | git submodule update --init --recursive --progress |
| 185 | } |
| 186 | |
| 187 | # install dep from source code |
| 188 | dep_install() { |
| 189 | local INFO=() |
| 190 | IFS=',' read -a INFO <<< "${DEP_INFO[$1]}" |
| 191 | local DLDIR="${CODEROOT}/${INFO[0]}" |
| 192 | if dep_exists $1 || ! [[ -d "$DLDIR" ]]; then |
| 193 | return |
| 194 | fi |
| 195 | pushd "$DLDIR" |
| 196 | |
| 197 | local FN="build_$1" |
| 198 | if declare -F $FN >/dev/null; then |
| 199 | echo "Installing ${INFO[1]} with custom command" |
| 200 | $FN |
| 201 | elif [[ -x waf ]]; then |
| 202 | echo "Installing ${INFO[1]} with Waf" |
| 203 | $PYTHON ./waf configure ${DEP_WAFOPTS[$1]} |
| 204 | $PYTHON ./waf -j${NJOBS} |
| 205 | $SUDO $PYTHON ./waf install |
| 206 | fi |
| 207 | popd |
| 208 | } |
| 209 | |
| 210 | if [[ $PPA_AVAIL -ne 1 ]] || [[ $NO_PPA -eq 1 ]]; then |
| 211 | PREFER_FROM=source |
| 212 | fi |
| 213 | |
| 214 | # dep install order, excluding ndn-cxx |
| 215 | DEPLIST=(NFD PSYNC NLSR TOOLS TRAFFIC INFOEDIT MININET) |
| 216 | if [[ $NO_WIFI -ne 1 ]]; then |
| 217 | DEPLIST+=(MNWIFI) |
| 218 | fi |
| 219 | |
| 220 | echo "Will download to ${CODEROOT}" |
| 221 | echo 'Will install compiler and build tools' |
| 222 | dep_prompt CXX |
| 223 | if [[ $CXX_DUMMY_KEYCHAIN -eq 1 ]]; then |
| 224 | echo 'Will patch ndn-cxx to use dummy KeyChain' |
| 225 | fi |
| 226 | for DEP in "${DEPLIST[@]}"; do |
| 227 | dep_prompt $DEP |
| 228 | done |
| 229 | if [[ $DL_ONLY -ne 1 ]]; then |
| 230 | echo "Will compile with ${NJOBS} parallel jobs" |
| 231 | echo "Will install Mini-NDN package" |
| 232 | fi |
| 233 | |
| 234 | if [[ $CONFIRM -ne 1 ]]; then |
| 235 | read -p 'Press ENTER to continue or CTRL+C to abort ' |
| 236 | fi |
| 237 | |
| 238 | install_pkgs |
| 239 | |
| 240 | if [[ -z $SKIPPYTHONCHECK ]]; then |
| 241 | PYTHON_VERSION=$($PYTHON --version) |
| 242 | SUDO_PYTHON_VERSION=$($SUDO $PYTHON --version) |
| 243 | if [[ "$PYTHON_VERSION" != "$SUDO_PYTHON_VERSION" ]]; then |
| 244 | cat <<EOT |
| 245 | In your system, '${PYTHON}' is ${PYTHON_VERSION} and '$SUDO ${PYTHON}' is ${SUDO_PYTHON_VERSION} |
| 246 | You must manually resolve the conflict, e.g. delete excess Python installation or change $PATH |
| 247 | To bypass this check, set the environment variable SKIPPYTHONCHECK=1 |
| 248 | EOT |
| 249 | exit 1 |
| 250 | fi |
| 251 | fi |
| 252 | |
| 253 | if ! mkdir -p "${CODEROOT}" 2>/dev/null; then |
| 254 | $SUDO mkdir -p "${CODEROOT}" |
| 255 | $SUDO chown $(id -u) "${CODEROOT}" |
| 256 | fi |
| 257 | dep_checkout CXX |
| 258 | if [[ $CXX_DUMMY_KEYCHAIN -eq 1 ]]; then |
| 259 | echo 'Patching ndn-cxx to use dummy KeyChain' |
| 260 | if ! git -C "${CODEROOT}/ndn-cxx" apply --index < "${PKGDEPDIR}/../patches/ndn-cxx-dummy-keychain.patch"; then |
| 261 | echo 'Cannot patch ndn-cxx to use dummy KeyChain (possibly already patched)' |
| 262 | fi |
| 263 | fi |
| 264 | for DEP in "${DEPLIST[@]}"; do |
| 265 | dep_checkout $DEP |
| 266 | done |
| 267 | |
| 268 | if [[ $DL_ONLY -eq 1 ]]; then |
| 269 | cat <<EOT |
| 270 | Source code has been downloaded to ${CODEROOT} |
| 271 | You may make changes or checkout different versions |
| 272 | Run this script again without --dl-only to install from local checkout |
| 273 | EOT |
| 274 | exit 0 |
| 275 | fi |
| 276 | |
| 277 | prepare_ld |
| 278 | for DEP in CXX "${DEPLIST[@]}"; do |
| 279 | dep_install $DEP |
| 280 | done |
| 281 | $SUDO ldconfig |
| 282 | |
| 283 | DESTDIR=/usr/local/etc/mini-ndn |
| 284 | $SUDO install -d -m0755 "$DESTDIR" |
| 285 | find topologies/ -name '*.conf' | xargs $SUDO install -m0644 -t "$DESTDIR/" |
| 286 | $SUDO $PYTHON setup.py develop |
| 287 | |
| 288 | echo 'MiniNDN installation completed successfully' |