Commits

Crispin Wellington committed 4ad66a9

create hashes from requirements files

Comments (0)

Files changed (2)

parcel/requirements.py

+# -*- coding: utf-8 -*-
+import os.path
+import hashlib
+
+class Requirements(object):
+    """A simple :class:`Requirements <Requirements>` object. Doesn't attempt to replicate pip totally,
+    but understands nested requirements files somewhat and can hash the requirements contents
+    """
+    
+    def __init__(self):
+        self.files = {}
+
+    def load(self, file="requirements.txt"):
+        """Read in all the requirements files."""
+        self.files.update( self._load(file) )
+
+    def _load(self, file):
+        with open(file) as fh:
+            data = fh.read()
+
+        output = { file: data }
+
+        for line in data.splitlines():
+            if line.strip() and line.strip().split()[0] == "-r":
+                output.update( self._load(line.strip().split()[1]) )
+
+        return output
+
+    def hash_set(self):
+        def _hash(data):
+            sha = hashlib.sha1()
+            sha.update(data)
+            return sha.hexdigest()
+
+        # hash each file
+        return { filename:_hash(self.files[filename]) for filename in self.files }
+
+    def hash(self):
+        """Return a global hash representing all the files"""
+        #digest all the data in alphabetical order
+        sha = hashlib.sha1()
+        for filename in sorted(self.files):
+            sha.update(filename)
+            sha.update(self.files[filename])
+
+        return sha.hexdigest()
+
+                     
+
+
+        

tests/test_requirements.py

+import unittest
+
+from parcel.requirements import Requirements
+from tempdir import TempDir
+
+EXAMPLE_REQUIREMENTS = { 'requirements.txt' : """fabric>=1.4.3
+requests
+""",
+                                          'test-requirements.txt' : """# the parcel requirements
+-r requirements.txt
+
+# stuff for testing
+mock
+nose
+unittest2
+coverage==3.5.3
+
+-e git://github.com/kennethreitz/envoy.git#egg=envoy
+""" }
+
+class RequirementsTestSuite(unittest.TestCase):
+    """Requirements test cases."""
+
+    def test_instantiate(self):
+        Requirements()
+
+    def test_load(self):
+        with TempDir(create=True, files=EXAMPLE_REQUIREMENTS ):
+            r = Requirements()
+            r.load("test-requirements.txt")
+            
+            # should have both files
+            self.assertIn("test-requirements.txt", r.files)
+            self.assertIn("requirements.txt", r.files)
+
+            original = r.files.copy()
+
+            # loading requirments over the top shouldn't change anything
+            r.load("requirements.txt")
+
+            # again both files. nothing changes.
+            self.assertEquals(original, r.files)
+            
+            # starting fresh with just requirements, should only get requirements
+            r2 = Requirements()
+            r2.load("requirements.txt")
+            self.assertNotIn("test-requirements.txt", r2.files)
+            self.assertIn("requirements.txt", r2.files)
+            
+    def test_hashes(self):
+        with TempDir(create=True, files=EXAMPLE_REQUIREMENTS ):
+            r = Requirements()
+            r.load("test-requirements.txt")
+
+            self.assertEquals( r.hash_set(),
+                               { 'requirements.txt':'08d35f8f7c040ef4f28321a84b37de50698eb750',
+                                 'test-requirements.txt':'66c6ab2c68bc68a67184ddbedd6cb78e8f1c1138' })
+        
+    
+    def test_hash(self):
+        with TempDir(create=True, files=EXAMPLE_REQUIREMENTS ):
+            r = Requirements()
+            r.load("test-requirements.txt")
+
+            self.assertEquals( r.hash(), 'b60512a2e67b5861f68d19b83560c0e1a743f357' )
+