Improved onos-setup-p4-dev

Now checks last built commit before building a project. Helpful when
dealing with frequent project updates (such as bmv2 o4 p4runtime).

Change-Id: I93ef9e63dc2f2b3a8ab5ef8e5356c476ca24487b
diff --git a/tools/dev/bin/onos-setup-p4-dev b/tools/dev/bin/onos-setup-p4-dev
index 33d9578..f3a1992 100755
--- a/tools/dev/bin/onos-setup-p4-dev
+++ b/tools/dev/bin/onos-setup-p4-dev
@@ -8,151 +8,215 @@
 # Recommended minimum system requirements:
 # 4 GB of RAM
 # 2 cores
-# > 5 GB free hard drive space (~4 GB to build everything)
+# 8 GB free hard drive space (~4 GB to build everything)
 # -----------------------------------------------------------------------------
 
 # Exit on errors.
 set -e
 
+BUILD_DIR=~/p4tools
 BMV2_COMMIT="487ee8f907153d93d4806f3e9e209ed9cb668c2b"
 PI_COMMIT="d7418b386e2301f82c1330a1d2dca131ef7b4fe3"
 P4C_COMMIT="80db63762314494b313f39c40067b3d3416007d3"
-PROTOBUF_VER="3.0.2"
-GRPC_VER="1.3.0"
+P4C_BM_COMMIT="8f4abeaa6f8374aaf95ea2aacfc2b750069391b5"
+PROTOBUF_COMMIT="tags/v3.0.2"
+GRPC_COMMIT="tags/v1.3.0"
 
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+NUM_CORES=`grep -c ^processor /proc/cpuinfo`
 
-cd ${DIR}
+function do_requirements {
+    sudo apt update
+    sudo apt install -y python-software-properties software-properties-common
+    sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
+    sudo apt update
+    sudo apt install -y \
+        autoconf \
+        automake \
+        bison \
+        curl \
+        dpkg-dev \
+        flex \
+        g++-4.9 \
+        gcc-4.9 \
+        git \
+        libboost-dev \
+        libboost-iostreams-dev \
+        libfl-dev \
+        libgc-dev \
+        libgmp-dev \
+        libreadline6 \
+        libreadline6-dev \
+        libtool \
+        libc6-dev \
+        make \
+        pkg-config \
+        python \
+        python-ipaddr \
+        python-scapy \
+        tcpdump \
+        unzip
 
-sudo apt update
-sudo apt install -y python-software-properties software-properties-common
-sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
-sudo apt update
-sudo apt install -y \
-    autoconf \
-    automake \
-    bison \
-    curl \
-    dpkg-dev \
-    flex \
-    g++-4.9 \
-    gcc-4.9 \
-    git \
-    libboost-dev \
-    libboost-iostreams-dev \
-    libfl-dev \
-    libgc-dev \
-    libgmp-dev \
-    libreadline6 \
-    libreadline6-dev \
-    libtool \
-    libc6-dev \
-    make \
-    pkg-config \
-    python \
-    python-ipaddr \
-    python-scapy \
-    tcpdump \
-    unzip
+    # Needed for p4c.
+    sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 50
+    sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 50
+}
 
-# Needed for p4c.
-sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 50
-sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 50
+function do_protobuf {
+    # Protobuf
+    cd ${BUILD_DIR}
+    if [ ! -d protobuf ]; then
+      git clone https://github.com/google/protobuf.git
+    fi
+    cd protobuf
+    git fetch
+    git checkout ${PROTOBUF_COMMIT}
+    ./autogen.sh
+    ./configure --prefix=/usr
+    make -j${NUM_CORES}
+    sudo make install
+    sudo ldconfig
+}
 
-# Protobuf
-if [ ! -d protobuf ]; then
-  git clone https://github.com/google/protobuf.git
-fi
-cd protobuf
-git fetch
-git checkout tags/v${PROTOBUF_VER}
-./autogen.sh
-./configure --prefix=/usr
-make -j2
-sudo make install
-sudo ldconfig
+function do_grpc {
+    # gRPC
+    cd ${BUILD_DIR}
+    if [ ! -d grpc ]; then
+      git clone https://github.com/grpc/grpc.git
+    fi
+    cd grpc
+    git fetch
+    git checkout ${GRPC_COMMIT}
+    git submodule update --init
+    make -j${NUM_CORES}
+    sudo make install
+    sudo ldconfig
+}
 
-# gRPC
-cd ${DIR}
-if [ ! -d grpc ]; then
-  git clone https://github.com/grpc/grpc.git
-fi
-cd grpc
-git fetch
-git checkout tags/v${GRPC_VER}
-git submodule update --init
-make -j2
-sudo make install
-sudo ldconfig
+function do_bmv2 {
+    # BMv2 part 1 (without PI)
+    cd ${BUILD_DIR}
+    if [ ! -d bmv2 ]; then
+        git clone https://github.com/p4lang/behavioral-model.git bmv2
+    fi
+    cd bmv2
+    git fetch
+    git checkout ${BMV2_COMMIT}
+    ./install_deps.sh
+    ./autogen.sh
+    ./configure --enable-debugger
+    make -j${NUM_CORES}
+    sudo make install
+    sudo ldconfig
+}
 
-# BMv2 part 1 (without PI)
-cd ${DIR}
-if [ ! -d bmv2 ]; then
-    git clone https://github.com/p4lang/behavioral-model.git bmv2
-fi
-cd bmv2
-git fetch
-git checkout ${BMV2_COMMIT}
-./install_deps.sh
-./autogen.sh
-./configure --enable-debugger
-make -j2
-sudo make install
-sudo ldconfig
+function do_p4runtime {
+    # P4Runtime (PI)
+    cd ${BUILD_DIR}
+    if [ ! -d p4runtime ]; then
+        git clone https://github.com/p4lang/PI.git p4runtime
+    fi
+    cd p4runtime
+    git fetch
+    git checkout ${PI_COMMIT}
+    git submodule update --init --recursive
+    ./autogen.sh
+    ./configure --with-bmv2 --with-proto
+    make -j${NUM_CORES}
+    sudo make install
+    sudo ldconfig
+}
 
-# P4Runtime (PI)
-cd ${DIR}
-if [ ! -d p4runtime ]; then
-    git clone https://github.com/p4lang/PI.git p4runtime
-fi
-cd p4runtime
-git fetch
-git checkout ${PI_COMMIT}
-git submodule update --init --recursive
-./autogen.sh
-./configure --with-bmv2 --with-proto
-make -j2
-sudo make install
-sudo ldconfig
+function do_bmv2_with_pi {
+    # BMv2 part 2 (with PI)
+    cd ${BUILD_DIR}/bmv2
+    ./configure --enable-debugger --with-pi
+    make -j${NUM_CORES}
+    sudo make install
+    sudo ldconfig
 
-# BMv2 part 2 (with PI)
-cd ${DIR}/bmv2
-./configure --enable-debugger --with-pi
-make -j2
-sudo make install
-sudo ldconfig
+    # Simple_switch_grpc target
+    cd targets/simple_switch_grpc
+    ./autogen.sh
+    ./configure
+    make -j${NUM_CORES}
+    sudo make install
+    sudo ldconfig
+}
 
-# Simple_switch_grpc target
-cd targets/simple_switch_grpc
-./autogen.sh
-./configure
-make -j2
-sudo make install
-sudo ldconfig
+function do_p4c {
+    # p4c
+    cd ${BUILD_DIR}
+    if [ ! -d p4c ]; then
+        git clone https://github.com/p4lang/p4c.git
+    fi
+    cd p4c
+    git fetch
+    git checkout ${P4C_COMMIT}
+    git submodule update --init --recursive
+    ./bootstrap.sh
+    cd build
+    make -j${NUM_CORES}
+    sudo make install
+    sudo ldconfig
+}
 
-# p4c
-cd ${DIR}
-if [ ! -d p4c ]; then
-    git clone https://github.com/p4lang/p4c.git
-fi
-cd p4c
-git fetch
-git checkout ${P4C_COMMIT}
-git submodule update --init --recursive
-./bootstrap.sh
-cd build
-make -j2
-sudo make install
-sudo ldconfig
+function do_p4c_bm {
+    # p4c-bmv2 (old BMv2 compiler)
+    cd ${BUILD_DIR}
+    if [ ! -d p4c-bmv2 ]; then
+        git clone https://github.com/p4lang/p4c-bm.git p4c-bmv2
+    fi
+    cd p4c-bmv2
+    git fetch
+    git checkout ${P4C_BM_COMMIT}
+    sudo pip install -r requirements.txt
+    sudo python setup.py install
+}
 
-# p4c-bmv2 (old BMv2 compiler)
-cd ${DIR}
-if [ ! -d p4c-bmv2 ]; then
-    git clone https://github.com/p4lang/p4c-bm.git p4c-bmv2
-fi
-cd p4c-bmv2
-git fetch
-sudo pip install -r requirements.txt
-sudo python setup.py install
+function check_commit {
+    if [ ! -e $2 ]; then
+        return 0 # true
+    fi
+    if [[ $(< $2) != "$1" ]]; then
+        return 0 # true
+    fi
+    return 1 # false
+}
 
-echo "DONE!"
\ No newline at end of file
+MUST_DO_ALL=false
+DID_REQUIREMENTS=false
+function check_and_do {
+    # Check if the latest built commit is the same we are trying to build now, or if all projects
+    # must be built. If true builds this project.
+    commit_id="$1"
+    proj_dir="$2"
+    func_name="$3"
+    if ${MUST_DO_ALL} = true || check_commit ${commit_id} ${proj_dir}/.last_built_commit; then
+        echo "#"
+        echo "# Building ${proj_dir} (${commit_id})"
+        echo "#"
+        if ! ${DID_REQUIREMENTS} = true; then
+            do_requirements
+            DID_REQUIREMENTS=true
+        fi
+        eval ${func_name}
+        echo ${commit_id} > ${BUILD_DIR}/${proj_dir}/.last_built_commit
+        # Build all next projects as they might depend on this one.
+        MUST_DO_ALL=true
+    else
+        echo "${proj_dir} is up to date (commit ${commit_id})"
+    fi
+}
+
+mkdir -p ${BUILD_DIR}
+cd ${BUILD_DIR}
+# In dependency order.
+check_and_do ${PROTOBUF_COMMIT} protobuf do_protobuf
+check_and_do ${GRPC_COMMIT} grpc do_grpc
+check_and_do ${BMV2_COMMIT} bmv2 do_bmv2
+check_and_do ${PI_COMMIT} p4runtime do_p4runtime
+check_and_do ${BMV2_COMMIT} bmv2 do_bmv2_with_pi
+check_and_do ${P4C_COMMIT} p4c do_p4c
+check_and_do ${P4C_BM_COMMIT} p4c-bmv2 do_p4c_bm
+
+echo "Done!"