CORD-2741 implement VERSION file discovery for xos python libraries

Change-Id: Ife67b0066d5fd54958e1b1de3c5b3758ac9d3ca6
diff --git a/lib/xos-util/xosutil/autoversion_setup.py b/lib/xos-util/xosutil/autoversion_setup.py
new file mode 100644
index 0000000..5a7ea44
--- /dev/null
+++ b/lib/xos-util/xosutil/autoversion_setup.py
@@ -0,0 +1,74 @@
+
+# Copyright 2017-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.
+
+"""
+ xosutil/autoversion_setup.py
+
+ This module exports a function, setup_with_auto_version(), that will automatically generate a version.py file
+ dynamically from the version option passed to the setup function. It does this without having to modify the
+ source copy of version.py.
+
+ It also automatically searches for VERSION files in the directory of the caller and its parent hierarchy, and will
+ automatically load the version number from the VERSION file, if one is detected.
+"""
+
+import os
+from setuptools import setup
+
+from setuptools.command.sdist import sdist
+from setuptools.command.build_py import build_py
+
+import inspect
+from autodiscover_version import autodiscover_version
+
+class SdistCommand(sdist):
+    def copy_file(self, infile, outfile, *args, **kwargs):
+        if kwargs.get("dry_run"):
+            return (outfile, 1)
+        if (os.path.split(outfile)[1] == "version.py"):
+            open(outfile, "w").write("# do not edit. Autogenerated file.\n" \
+                                     "__version__ = '%s'\n" % self.distribution.metadata.version)
+            return (outfile, 1)
+        else:
+            return sdist.copy_file(self, infile, outfile, *args, **kwargs)
+
+class BuildPyCommand(build_py):
+    def copy_file(self, infile, outfile, *args, **kwargs):
+        if kwargs.get("dry_run"):
+            return (outfile, 1)
+        if (os.path.split(outfile)[1] == "version.py"):
+            open(outfile, "w").write("# do not edit. Autogenerated file.\n" \
+                                     "__version__ = '%s'\n" % self.distribution.metadata.version)
+            return (outfile, 1)
+        else:
+            return build_py.copy_file(self, infile, outfile, *args, **kwargs)
+
+def setup_with_auto_version(*args, **kwargs):
+    # Learn the module that called this function, so we can search for any VERSION files in it.
+    frame = inspect.stack()[1]
+    caller_module = inspect.getmodule(frame[0])
+
+    # Search for a VERSION file and extract the version number from it.
+    version = autodiscover_version(caller_filename = caller_module.__file__)
+    if version:
+        kwargs["version"] = version
+
+    cmdclass = kwargs.get("cmdclass", {}).copy()
+    cmdclass.update( {"sdist": SdistCommand,
+                "build_py": BuildPyCommand} )
+    kwargs["cmdclass"] = cmdclass
+
+    return setup(*args, **kwargs)
+