Store URI as part of the Entity object

Signed-off-by: martin f. krafft <madduck@madduck.net>

Conflicts:
	reclass/storage/__init__.py
diff --git a/reclass/datatypes/entity.py b/reclass/datatypes/entity.py
index 727b828..0540074 100644
--- a/reclass/datatypes/entity.py
+++ b/reclass/datatypes/entity.py
@@ -13,20 +13,22 @@
 class Entity(object):
     '''
     A collection of Classes, Parameters, and Applications, mainly as a wrapper
-    for merging. The name of an Entity will be updated to the name of the
-    Entity that is being merged.
+    for merging. The name and uri of an Entity will be updated to the name and
+    uri of the Entity that is being merged.
     '''
     def __init__(self, classes=None, applications=None, parameters=None,
-                 name=None):
+                 uri=None, name=None):
         if classes is None: classes = Classes()
         self._set_classes(classes)
         if applications is None: applications = Applications()
         self._set_applications(applications)
         if parameters is None: parameters = Parameters()
         self._set_parameters(parameters)
+        self._uri = uri or ''
         self._name = name or ''
 
     name = property(lambda s: s._name)
+    uri = property(lambda s: s._uri)
     classes = property(lambda s: s._classes)
     applications = property(lambda s: s._applications)
     parameters = property(lambda s: s._parameters)
@@ -54,6 +56,7 @@
         self._applications.merge_unique(other._applications)
         self._parameters.merge(other._parameters)
         self._name = other.name
+        self._uri = other.uri
 
     def interpolate(self):
         self._parameters.interpolate()
@@ -63,15 +66,19 @@
                 and self._applications == other._applications \
                 and self._classes == other._classes \
                 and self._parameters == other._parameters \
-                and self._name == other._name
+                and self._name == other._name \
+                and self._uri == other._uri
 
     def __ne__(self, other):
         return not self.__eq__(other)
 
     def __repr__(self):
-        return "%s(%r, %r, %r, %r)" % (self.__class__.__name__,
-                                         self.classes, self.applications,
-                                         self.parameters, self.name)
+        return "%s(%r, %r, %r, uri=%r, name=%r)" % (self.__class__.__name__,
+                                                    self.classes,
+                                                    self.applications,
+                                                    self.parameters,
+                                                    self.uri,
+                                                    self.name)
 
     def as_dict(self):
         return {'classes': self._classes.as_list(),
diff --git a/reclass/datatypes/tests/test_entity.py b/reclass/datatypes/tests/test_entity.py
index 50e5669..1bc1f6b 100644
--- a/reclass/datatypes/tests/test_entity.py
+++ b/reclass/datatypes/tests/test_entity.py
@@ -26,6 +26,7 @@
         # all other tests shall pass instances to the constructor
         e = Entity()
         self.assertEqual(e.name, '')
+        self.assertEqual(e.uri, '')
         self.assertIsInstance(e.classes, Classes)
         self.assertIsInstance(e.applications, Applications)
         self.assertIsInstance(e.parameters, Parameters)
@@ -34,6 +35,7 @@
         instances = self._make_instances(**types)
         e = Entity(*instances)
         self.assertEqual(e.name, '')
+        self.assertEqual(e.uri, '')
         cl, al, pl = [getattr(i, '__len__') for i in instances]
         self.assertEqual(len(e.classes), cl.return_value)
         cl.assert_called_once_with()
@@ -47,6 +49,11 @@
         e = Entity(*self._make_instances(**types), name=name)
         self.assertEqual(e.name, name)
 
+    def test_constructor_empty_uri(self, **types):
+        uri = 'test://uri'
+        e = Entity(*self._make_instances(**types), uri=uri)
+        self.assertEqual(e.uri, uri)
+
     def test_equal_empty(self, **types):
         instances = self._make_instances(**types)
         self.assertEqual(Entity(*instances), Entity(*instances))
@@ -62,9 +69,17 @@
 
     def test_unequal_empty_named(self, **types):
         instances = self._make_instances(**types)
+        uri = 'test://uri'
+        self.assertNotEqual(Entity(*instances, uri=uri),
+                            Entity(*instances, name=uri[::-1]))
+        for i in instances:
+            i.__eq__.assert_called_once_with(i)
+
+    def test_unequal_empty_named(self, **types):
+        instances = self._make_instances(**types)
         name = 'empty'
-        self.assertNotEqual(Entity(*instances, name='empty'),
-                            Entity(*instances, name='ytpme'))
+        self.assertNotEqual(Entity(*instances, name=name),
+                            Entity(*instances, name=name[::-1]))
         for i in instances:
             i.__eq__.assert_called_once_with(i)
 
@@ -104,6 +119,14 @@
         e1.merge(e2)
         self.assertEqual(e1.name, newname)
 
+    def test_merge_newuri(self, **types):
+        instances = self._make_instances(**types)
+        newuri = 'test://uri2'
+        e1 = Entity(*instances, uri='test://uri1')
+        e2 = Entity(*instances, uri=newuri)
+        e1.merge(e2)
+        self.assertEqual(e1.uri, newuri)
+
     def test_as_dict(self, **types):
         instances = self._make_instances(**types)
         entity = Entity(*instances, name='test')
diff --git a/reclass/storage/__init__.py b/reclass/storage/__init__.py
index 3283c09..c2161e1 100644
--- a/reclass/storage/__init__.py
+++ b/reclass/storage/__init__.py
@@ -48,7 +48,7 @@
                 try:
                     class_entity = self._classes_cache[klass]
                 except KeyError, e:
-                    class_entity, uri = self._get_class(klass)
+                    class_entity = self._get_class(klass)
                     self._classes_cache[klass] = class_entity
 
                 descent = self._recurse_entity(class_entity, seen=seen,
@@ -65,14 +65,14 @@
         return merge_base
 
     def _nodeinfo(self, nodename):
-        node_entity, uri = self._get_node(nodename)
+        node_entity = self._get_node(nodename)
         merge_base = Entity(name='merge base for {0}'.format(nodename))
         ret = self._recurse_entity(node_entity, merge_base, nodename=nodename)
         ret.interpolate()
-        return ret, uri
+        return ret
 
-    def _nodeinfo_as_dict(self, nodename, entity, uri):
-        ret = {'__reclass__' : {'node': nodename, 'uri': uri,
+    def _nodeinfo_as_dict(self, nodename, entity):
+        ret = {'__reclass__' : {'node': nodename, 'uri': entity.uri,
                                 'timestamp': _get_timestamp()
                                 },
               }
@@ -80,7 +80,7 @@
         return ret
 
     def nodeinfo(self, nodename):
-        return self._nodeinfo_as_dict(nodename, *self._nodeinfo(nodename))
+        return self._nodeinfo_as_dict(nodename, self._nodeinfo(nodename))
 
     def _list_inventory(self):
         raise NotImplementedError, "Storage class does not implement inventory listing"
@@ -91,8 +91,8 @@
         nodes = {}
         applications = {}
         classes = {}
-        for f, (nodeinfo, uri) in entities.iteritems():
-            d = nodes[f] = self._nodeinfo_as_dict(f, nodeinfo, uri)
+        for f, nodeinfo in entities.iteritems():
+            d = nodes[f] = self._nodeinfo_as_dict(f, nodeinfo)
             for a in d['applications']:
                 if a in applications:
                     applications[a].append(f)
diff --git a/reclass/storage/yaml_fs/__init__.py b/reclass/storage/yaml_fs/__init__.py
index 798847e..6569709 100644
--- a/reclass/storage/yaml_fs/__init__.py
+++ b/reclass/storage/yaml_fs/__init__.py
@@ -59,7 +59,7 @@
             raise reclass.errors.NodeNotFound(self._get_storage_name(),
                                               name, self.nodes_uri)
         entity = YamlFile(path).entity
-        return entity, 'file://{0}'.format(path)
+        return entity
 
     def _get_class(self, name, nodename=None):
         vvv('GET CLASS {0}'.format(name))
@@ -70,7 +70,7 @@
                                                name, self.classes_uri,
                                                nodename)
         entity = YamlFile(path).entity
-        return entity, 'file://{0}'.format(path)
+        return entity
 
     def _list_inventory(self):
         entities = {}
diff --git a/reclass/storage/yaml_fs/yamlfile.py b/reclass/storage/yaml_fs/yamlfile.py
index f9bd819..54c1a7e 100644
--- a/reclass/storage/yaml_fs/yamlfile.py
+++ b/reclass/storage/yaml_fs/yamlfile.py
@@ -48,7 +48,8 @@
         parameters = datatypes.Parameters(parameters)
 
         return datatypes.Entity(classes, applications, parameters,
-                                name='yaml_fs://{0}'.format(self._path))
+                                name=self._path,
+                                uri='yaml_fs://{0}'.format(self._path))
     entity = property(lambda self: self._get_entity())
 
     def __repr__(self):