MirrorGitRepository: methods for setting/getting ref
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Wed, 5 Mar 2014 11:48:39 +0000 (13:48 +0200)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Wed, 5 Mar 2014 12:35:49 +0000 (14:35 +0200)
Implement methods for setting and getting refs.  These handle symbolic
and non-symbolic refs automatically.

Change-Id: Idc3dcc389722c569ddc725097115408455de498a
Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
gbp_repocache/__init__.py
tests/test_gbp_repocache.py

index 122888a8324a42da10102861e5ba0cdf94a29a48..ade3e89ca88f6417d500032aef9f210eba31803f 100644 (file)
@@ -44,6 +44,28 @@ class MirrorGitRepository(GitRepository): # pylint: disable=R0904
             raise GitRepositoryError('Failed to set config %s=%s (%s)' %
                                      (name, value, stderr))
 
+    def get_ref(self, ref):
+        """Get a ref - i.e. where it points to"""
+        stdout, _stderr, ret = self._git_inout('symbolic-ref', [ref])
+        if ret:
+            return self.rev_parse(ref)
+        else:
+            return stdout.splitlines()[0]
+
+    def set_ref(self, ref, value):
+        """Change a ref"""
+        if value.startswith('refs/'):
+            _stdout, stderr, ret = self._git_inout('symbolic-ref', [ref, value])
+            if ret:
+                raise GitRepositoryError('Failed to set symbolic ref: %s' %
+                                         stderr)
+        else:
+            # Write directly to the file. This is not as intelligent as
+            # git-update-ref but this way we can set the ref to anything
+            # (e.g. an non-existent sha-1)
+            with open(os.path.join(self.git_dir, ref), 'w') as ref_file:
+                ref_file.write(value + '\n')
+
     def force_fetch(self):
         """Fetch with specific arguments"""
         # Update all refs
@@ -53,8 +75,8 @@ class MirrorGitRepository(GitRepository): # pylint: disable=R0904
             self._git_command('fetch', ['-q', '-u', 'origin', 'HEAD'])
         except GitRepositoryError:
             # If remote HEAD is invalid, invalidate FETCH_HEAD, too
-            with open(os.path.join(self.git_dir, 'FETCH_HEAD'), 'w') as fhead:
-                fhead.write('0000000000000000000000000000000000000000\n')
+            self.set_ref('FETCH_HEAD',
+                         '0000000000000000000000000000000000000000')
 
     def force_checkout(self, commitish):
         """Checkout commitish"""
@@ -229,8 +251,8 @@ class CachedRepo(object):
         # Update HEAD from FETCH_HEAD, so that HEAD points to remote HEAD.
         # We do it this way because FETCH_HEAD may point to an invalid object
         # and we don't want to update the working copy at this point.
-        shutil.copyfile(os.path.join(self.repo.git_dir, 'FETCH_HEAD'),
-                        os.path.join(self.repo.git_dir, 'HEAD'))
+        self.repo.set_ref('HEAD', self.repo.get_ref('FETCH_HEAD'))
+
         # Clean: just in case - this should never ever really be necessary
         # unless somebody manually hacks the cached repository introducing
         # local changes
index fad343d8cdb8cec6ebfb3bd22d523f90b2235298..83a1342e9870aec111545174bbe9e28b04d7337f 100644 (file)
@@ -41,6 +41,22 @@ class TestMirrorGitRepository(UnitTestsBase):
         repo.set_config('foo.bar', 'bax', replace=True)
         eq_(repo.get_config('foo.bar'), 'bax')
 
+    def test_get_set_ref(self):
+        """Test setting and getting ref"""
+        repo = MirrorGitRepository.clone('testrepo', self.orig_repo.path)
+        remote_head = 'refs/heads/' + self.orig_repo.get_branch()
+
+        eq_(repo.get_ref('HEAD'), remote_head)
+        with assert_raises(GitRepositoryError):
+            repo.get_ref('MY_REF')
+
+        repo.set_ref('MY_REF', repo.get_ref('HEAD'))
+        eq_(repo.get_ref('MY_REF'), remote_head)
+
+        sha1 = repo.rev_parse('HEAD')
+        repo.set_ref('MY_REF', sha1)
+        eq_(repo.get_ref('MY_REF'), sha1)
+
 
 class TestCachedRepo(UnitTestsBase):
     """Test CachedRepo class"""