[SDFAB-872] Allow to use local maven cache via env variable

If USE_LOCAL_SNAPSHOT_ARTIFACTS=true while we are building from source code, it will use the 
snapshot artifacts in local maven cache rather than fetching from remote repositories. It is not 
effective when we are not building from source code.

Change-Id: I10cbaac0601eff40b1a7cb7c45c532bb17914c0d
diff --git a/.gitignore b/.gitignore
index 3cb149b..cd04584 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@
 fabric-tna/
 .m2/
 mvn_settings.xml
+.onos-publish-local
diff --git a/Makefile b/Makefile
index 75216eb..ea7e806 100644
--- a/Makefile
+++ b/Makefile
@@ -63,6 +63,7 @@
 PROFILER                     ?=
 ONOS_YOURKIT                 := 2021.3-b230
 USE_ONOS_BAZEL_OUTPUT        ?=
+USE_LOCAL_SNAPSHOT_ARTIFACTS ?=
 
 # TOST related
 TOST_IMAGENAME               := ${DOCKER_REGISTRY}${DOCKER_REPOSITORY}tost:${DOCKER_TAG}${DOCKER_TAG_PROFILER}${DOCKER_TAG_BUILD_DATE}
@@ -142,7 +143,7 @@
 	fi \
 	fi
 
-trellis-control-build: mvn_settings.xml local-apps trellis-control  ## : Builds trellis-control using local app or mvn
+trellis-control-build: mvn_settings.xml .onos-publish-local local-apps trellis-control  ## : Builds trellis-control using local app or mvn
 	@./app-build.sh $@
 
 trellis-t3: ## : Checkout trellis-t3 code
@@ -164,7 +165,7 @@
 	fi \
 	fi
 
-trellis-t3-build: mvn_settings.xml local-apps trellis-t3  ## : Builds trellis-t3 using local app or mvn
+trellis-t3-build: mvn_settings.xml .onos-publish-local local-apps trellis-t3  ## : Builds trellis-t3 using local app or mvn
 	@./app-build.sh $@
 
 up4: ## : Checkout up4 code
@@ -187,7 +188,7 @@
 	fi \
 	fi
 
-up4-build: mvn_settings.xml local-apps up4  ## : Builds up4 using local app
+up4-build: mvn_settings.xml .onos-publish-local local-apps up4  ## : Builds up4 using local app
 	@./app-build.sh $@
 
 fabric-tna: ## : Checkout fabric-tna code
@@ -210,7 +211,7 @@
 	fi \
 	fi
 
-fabric-tna-build: mvn_settings.xml local-apps fabric-tna  ## : Builds fabric-tna using local app
+fabric-tna-build: mvn_settings.xml .onos-publish-local local-apps fabric-tna  ## : Builds fabric-tna using local app
 	@./app-build.sh $@
 
 apps: trellis-control trellis-t3 up4 fabric-tna ## : downloads commits, files, and refs from remotes
@@ -239,6 +240,7 @@
 	fi
 
 onos-build: onos ## : Builds the tost-onos docker image
+	rm -rf .onos-publish-local
 ifeq ($(PROFILER),true)
 	# profiler enabled
 	cd ${ONOS_ROOT} && \
@@ -260,6 +262,16 @@
 	docker build . -t ${ONOS_IMAGENAME} \
 	--build-arg PROFILE=${ONOS_PROFILE}
 endif
+	make .onos-publish-local
+
+.onos-publish-local:
+ifeq ($(USE_LOCAL_SNAPSHOT_ARTIFACTS),true)
+	@# TODO: build custom docker container with required dependencies instead of installing via publish-local script
+	docker run --rm --entrypoint bash -it -v $(shell pwd)/:/tost \
+	-e ONOS_ROOT=/tost/onos -e MAVEN_REPO=/tost/.m2/repository -w /tost \
+	bitnami/minideb:buster ./publish-local.sh
+endif
+	touch .onos-publish-local
 
 tost-build: ## : Builds the tost docker image
 	docker build $(DOCKER_BUILD_ARGS) \
@@ -299,5 +311,6 @@
 	rm -rf ${LOCAL_APPS}
 	rm -rf .m2
 	rm -rf mvn_settings.xml
+	rm -rf .onos-publish-local
 
 # end file
diff --git a/README.md b/README.md
index 762f296..943879f 100644
--- a/README.md
+++ b/README.md
@@ -57,6 +57,21 @@
 make tost-build
 ```
 
+### Build with custom ONOS API changes
+When doing ONOS API changes, we don't want to fetch ONOS maven artifacts from the
+remote sonatype SNAPSHOT repository. To do so, we need to set an environment variable
+(`USE_LOCAL_SNAPSHOT_ARTIFACTS=true`) and follow a specific order when building the
+`tost` image.
+
+1. ONOS (this will also publish the ONOS maven artifacts in  the local `.m2` folder):
+   `USE_LOCAL_SNAPSHOT_ARTIFACTS=true [DOCKER_TAG=master] make onos-build`
+2. Trellis Control, UP4:
+   `USE_LOCAL_SNAPSHOT_ARTIFACTS=true [DOCKER_TAG=master] make trellis-control-build up4-build`
+3. Trellis T3, Fabric TNA:
+   `USE_LOCAL_SNAPSHOT_ARTIFACTS=true [DOCKER_TAG=master] make fabric-tna-build trellis-t3-build`
+4. TOST:
+   `USE_LOCAL_SNAPSHOT_ARTIFACTS=true [DOCKER_TAG=master] make tost-build`
+
 ## Update
 
 Use `apps` or `appname` targets to downloads commits, files, and refs from remotes.
diff --git a/app-build.sh b/app-build.sh
index a94146f..ca9742f 100755
--- a/app-build.sh
+++ b/app-build.sh
@@ -127,10 +127,21 @@
 	"app/target" "${TRELLIS_CONTROL_OAR}" "${TRELLIS_CONTROL_REPO}"
 	# If MVN was not successful - built from sources
 	if [ "$MVN" -eq "0" ]; then
+		# When building from source api and app jars are automatically put into the local .m2 folder.
 		# Update VERSION
 		extract_version "${TRELLIS_CONTROL_ROOT}"
 		# Update OAR
 		TRELLIS_CONTROL_OAR="${TRELLIS_CONTROL_ROOT}"/app/target/"${TRELLIS_CONTROL_ARTIFACTID}"-"${PROJECT_VERSION}".oar
+	else
+		# Fetch trellis-control api and app JARs that may be needed to build other apps when using local maven cache (i.e., T3 and fabric-tna).
+		# Fetched jars will be places in the local .m2 folder.
+		docker run "${IT}" --rm -v "${CURRENT_DIR}":/root -w /root/"trellis-control" "${DOCKER_MVN_IMAGE}" \
+			bash -c "mvn dependency:copy -Dartifact=${TRELLIS_CONTROL_GROUPID}:segmentrouting-api:${TRELLIS_CONTROL_VERSION} \
+			-Dmdep.useBaseVersion=true -Dmdep.overWriteReleases=true -Dmdep.overWriteSnapshots=true -f dependencies.xml \
+			-s mvn_settings.xml; \
+			mvn dependency:copy -Dartifact=${TRELLIS_CONTROL_GROUPID}:segmentrouting-app:${TRELLIS_CONTROL_VERSION} \
+			-Dmdep.useBaseVersion=true -Dmdep.overWriteReleases=true -Dmdep.overWriteSnapshots=true -f dependencies.xml \
+			-s mvn_settings.xml"
 	fi
 	# Final step requires to move the oar to the folder used by the tost docker file. Moreover, it will help catch up errors
 	cp "${TRELLIS_CONTROL_OAR}" "${LOCAL_APPS}"/
diff --git a/dependencies.xml b/dependencies.xml
index 6bbcedd..e517437 100644
--- a/dependencies.xml
+++ b/dependencies.xml
@@ -40,7 +40,10 @@
         </repository>
 
         <repository>
-            <id>snapshots</id>
+            <!-- do not use "snapshots" repository name, otherwise when using
+              local maven cache it won't work since a fake mirror for snapshot
+              is added to the mvn_settings.xml -->
+            <id>snapshots-tost</id>
             <url>https://oss.sonatype.org/content/repositories/snapshots</url>
             <snapshots>
                 <enabled>true</enabled>
diff --git a/mvn_settings.sh b/mvn_settings.sh
index b2e72e0..846d827 100755
--- a/mvn_settings.sh
+++ b/mvn_settings.sh
@@ -52,6 +52,7 @@
           xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
   <!--PROXY-->
   <!--EXTRA-->
+  <!--MIRRORS-->
 </settings>
 EOF
 
@@ -82,6 +83,22 @@
   rm mvn_settings.proxy.xml
 fi
 
+if [ "$USE_LOCAL_SNAPSHOT_ARTIFACTS" == "true" ]; then
+  # When using local SNAPSHOT artifacts, we need to prevent maven to fetch from the Sonatype repository.
+  # However, we need to point to a valid maven repository otherwise maven fails. For this reason we
+  # mirror snapshots to maven central (that won't contain any SNAPSHOT artifacts).
+  echo "    <mirrors>
+      <mirror>
+        <id>central_snapshots</id>
+        <name>central_snapshots</name>
+        <url>https://repo.maven.apache.org/maven2</url>
+        <mirrorOf>snapshots</mirrorOf>
+      </mirror>
+    </mirrors>" >> mvn_settings.mirror.xml
+  sed -i '' -e '/<!--MIRRORS-->/r mvn_settings.mirror.xml' mvn_settings.xml
+  rm mvn_settings.mirror.xml
+fi
+
 if [ -f mvn_settings.extra.xml ] ; then
   sed -i 's/<!--EXTRA-->/r mvn_settings.extra.xml' mvn_settings.xml
 fi
diff --git a/publish-local.sh b/publish-local.sh
new file mode 100755
index 0000000..66e0e6f
--- /dev/null
+++ b/publish-local.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+#
+# Copyright 2022-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This script is run inside a container (minideb:buster) with ONOS codebase sitting in ONOS_ROOT env var
+set -eu -o pipefail
+
+# install dependencies required by the onos-publish script
+apt-get update && apt-get install -y curl build-essential python python-pip
+pip install requests
+curl -L -o bazelisk https://github.com/bazelbuild/bazelisk/releases/download/v1.5.0/bazelisk-linux-amd64
+chmod +x bazelisk && mv bazelisk /usr/bin/bazel
+
+#shellcheck source=/dev/null
+source "${ONOS_ROOT}"/tools/dev/bash_profile
+
+cd "${ONOS_ROOT}"
+onos-publish -l