[CORD-1480] Exposing xproto via gRPC

Change-Id: Id68bada0179a11d4296b7211f9f923c41c78470b
diff --git a/xos/coreapi/core_main.py b/xos/coreapi/core_main.py
index ada3222..93e5559 100644
--- a/xos/coreapi/core_main.py
+++ b/xos/coreapi/core_main.py
@@ -3,7 +3,8 @@
 import time
 
 import django
-sys.path.append('/opt/xos')
+xos_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/..')
+sys.path.append(xos_path)
 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
 
 from reaper import ReaperThread
@@ -14,6 +15,7 @@
 
 
 if __name__ == '__main__':
+
     django.setup()
 
     reaper = ReaperThread()
diff --git a/xos/coreapi/protos/.gitignore b/xos/coreapi/protos/.gitignore
new file mode 100644
index 0000000..f84f48e
--- /dev/null
+++ b/xos/coreapi/protos/.gitignore
@@ -0,0 +1,3 @@
+*_pb2_grpc.py
+*_pb2.py
+*.desc
\ No newline at end of file
diff --git a/xos/coreapi/protos/utility.proto b/xos/coreapi/protos/utility.proto
index 88dd8f1..1169b9d 100644
--- a/xos/coreapi/protos/utility.proto
+++ b/xos/coreapi/protos/utility.proto
@@ -42,6 +42,10 @@
     repeated ModelListEntry items = 1;
 };
 
+message XProtos {
+    string xproto = 1;
+};
+
 service utility {
 
   rpc Login(LoginRequest) returns (LoginResponse) {
@@ -98,4 +102,10 @@
             get: "/xosapi/v1/utility/dirty_models"
         };
   }
-};
+
+  rpc GetXproto(google.protobuf.Empty) returns (XProtos) {
+        option (google.api.http) = {
+            get: "/xosapi/v1/xproto"
+        };
+  }
+};
\ No newline at end of file
diff --git a/xos/coreapi/reaper.py b/xos/coreapi/reaper.py
index 879831e..3ea9c23 100644
--- a/xos/coreapi/reaper.py
+++ b/xos/coreapi/reaper.py
@@ -70,9 +70,9 @@
             deleted.
         """
         collector = XOSCollector(using=router.db_for_write(m.__class__, instance=m))
-        collector.collect([m])

-        deps=[]

-        for (k, models) in collector.data.items():

+        collector.collect([m])
+        deps=[]
+        for (k, models) in collector.data.items():
             for model in models:
                 if model==m:
                     # collector will return ourself; ignore it.
diff --git a/xos/coreapi/xos_utility_api.py b/xos/coreapi/xos_utility_api.py
index bce9bf0..46a5964 100644
--- a/xos/coreapi/xos_utility_api.py
+++ b/xos/coreapi/xos_utility_api.py
@@ -8,8 +8,8 @@
 from google.protobuf.empty_pb2 import Empty
 
 from importlib import import_module
-from django.conf import settings

-SessionStore = import_module(settings.SESSION_ENGINE).SessionStore

+from django.conf import settings
+SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
 
 from django.contrib.auth import authenticate as django_authenticate
 import django.apps
@@ -38,6 +38,13 @@
         return True
     return False
 
+def get_xproto(folder):
+    matches = []
+    for root, dirnames, filenames in os.walk(folder):
+        for filename in fnmatch.filter(filenames, '*.xproto'):
+            matches.append(os.path.join(root, filename))
+    return matches
+
 class UtilityService(utility_pb2.utilityServicer, XOSAPIHelperMixin):
     def __init__(self, thread_pool):
         self.thread_pool = thread_pool
@@ -183,3 +190,25 @@
 
         return dirty_models
 
+    @translate_exceptions
+    def GetXproto(self, request, context):
+        res = utility_pb2.XProtos()
+
+        core_dir = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/../core/models/')
+        core_xprotos = get_xproto(core_dir)
+
+        service_dir = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/../services')
+        services_xprotos = get_xproto(service_dir)
+
+        xprotos = core_xprotos + services_xprotos
+
+        xproto = ""
+
+        for f in xprotos:
+            content = open(f).read()
+            xproto += "\n"
+            xproto += content
+
+        res.xproto = xproto
+        return res
+