summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Client/Tools/VCS.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Bcfg2/Client/Tools/VCS.py')
-rw-r--r--src/lib/Bcfg2/Client/Tools/VCS.py119
1 files changed, 92 insertions, 27 deletions
diff --git a/src/lib/Bcfg2/Client/Tools/VCS.py b/src/lib/Bcfg2/Client/Tools/VCS.py
index 1ab867215..aca5dbbc7 100644
--- a/src/lib/Bcfg2/Client/Tools/VCS.py
+++ b/src/lib/Bcfg2/Client/Tools/VCS.py
@@ -1,14 +1,15 @@
"""VCS support."""
# TODO:
-# * git_write_index
# * add svn support
# * integrate properly with reports
missing = []
+import errno
import os
import shutil
import sys
+import stat
# python-dulwich git imports
try:
@@ -26,6 +27,38 @@ except ImportError:
import Bcfg2.Client.Tools
+def cleanup_mode(mode):
+ """Cleanup a mode value.
+
+ This will return a mode that can be stored in a tree object.
+
+ :param mode: Mode to clean up.
+ """
+ if stat.S_ISLNK(mode):
+ return stat.S_IFLNK
+ elif stat.S_ISDIR(mode):
+ return stat.S_IFDIR
+ elif dulwich.index.S_ISGITLINK(mode):
+ return dulwich.index.S_IFGITLINK
+ ret = stat.S_IFREG | int('644', 8)
+ ret |= (mode & int('111', 8))
+ return ret
+
+
+def index_entry_from_stat(stat_val, hex_sha, flags, mode=None):
+ """Create a new index entry from a stat value.
+
+ :param stat_val: POSIX stat_result instance
+ :param hex_sha: Hex sha of the object
+ :param flags: Index flags
+ """
+ if mode is None:
+ mode = cleanup_mode(stat_val.st_mode)
+ return (stat_val.st_ctime, stat_val.st_mtime, stat_val.st_dev,
+ stat_val.st_ino, mode, stat_val.st_uid,
+ stat_val.st_gid, stat_val.st_size, hex_sha, flags)
+
+
class VCS(Bcfg2.Client.Tools.Tool):
"""VCS support."""
__handles__ = [('Path', 'vcs')]
@@ -47,11 +80,24 @@ class VCS(Bcfg2.Client.Tools.Tool):
self.logger.info("Repository %s does not exist" %
entry.get('name'))
return False
- cur_rev = repo.head()
- if cur_rev != entry.get('revision'):
+ try:
+ expected_rev = entry.get('revision')
+ cur_rev = repo.head()
+ except:
+ return False
+
+ try:
+ client, path = dulwich.client.get_transport_and_path(entry.get('sourceurl'))
+ remote_refs = client.fetch_pack(path, (lambda x: None), None, None, None)
+ if expected_rev in remote_refs:
+ expected_rev = remote_refs[expected_rev]
+ except:
+ pass
+
+ if cur_rev != expected_rev:
self.logger.info("At revision %s need to go to revision %s" %
- (cur_rev, entry.get('revision')))
+ (cur_rev.strip(), expected_rev.strip()))
return False
return True
@@ -71,45 +117,64 @@ class VCS(Bcfg2.Client.Tools.Tool):
destname)
return False
- destr = dulwich.repo.Repo.init(destname, mkdir=True)
+ dulwich.file.ensure_dir_exists(destname)
+ destr = dulwich.repo.Repo.init(destname)
cl, host_path = dulwich.client.get_transport_and_path(entry.get('sourceurl'))
remote_refs = cl.fetch(host_path,
destr,
determine_wants=destr.object_store.determine_wants_all,
progress=sys.stdout.write)
- destr.refs['refs/heads/master'] = entry.get('revision')
- dtree = destr[entry.get('revision')].tree
- obj_store = destr.object_store
- for fname, mode, sha in obj_store.iter_tree_contents(dtree):
- fullpath = os.path.join(destname, fname)
- try:
- f = open(os.path.join(destname, fname), 'wb')
- except IOError:
- dir = os.path.split(fullpath)[0]
- os.makedirs(dir)
- f = open(os.path.join(destname, fname), 'wb')
- f.write(destr[sha].data)
- f.close()
- os.chmod(os.path.join(destname, fname), mode)
+
+ if entry.get('revision') in remote_refs:
+ destr.refs['HEAD'] = remote_refs[entry.get('revision')]
+ else:
+ destr.refs['HEAD'] = entry.get('revision')
+
+ dtree = destr['HEAD'].tree
+ index = dulwich.index.Index(destr.index_path())
+ for fname, mode, sha in destr.object_store.iter_tree_contents(dtree):
+ full_path = os.path.join(destname, fname)
+ dulwich.file.ensure_dir_exists(os.path.dirname(full_path))
+
+ if stat.S_ISLNK(mode):
+ src_path = destr[sha].as_raw_string()
+ try:
+ os.symlink(src_path, full_path)
+ except OSError:
+ e = sys.exc_info()[1]
+ if e.errno == errno.EEXIST:
+ os.unlink(full_path)
+ os.symlink(src_path, full_path)
+ else:
+ raise
+ else:
+ file = open(full_path, 'wb')
+ file.write(destr[sha].as_raw_string())
+ file.close()
+ os.chmod(full_path, mode)
+
+ st = os.lstat(full_path)
+ index[fname] = index_entry_from_stat(st, sha, 0)
+
+ index.write()
return True
- # FIXME: figure out how to write the git index properly
- #iname = "%s/.git/index" % entry.get('name')
- #f = open(iname, 'w+')
- #entries = obj_store[sha].iteritems()
- #try:
- # dulwich.index.write_index(f, entries)
- #finally:
- # f.close()
def Verifysvn(self, entry, _):
"""Verify svn repositories"""
+ headrev = pysvn.Revision( pysvn.opt_revision_kind.head )
client = pysvn.Client()
try:
cur_rev = str(client.info(entry.get('name')).revision.number)
+ server = client.info2(entry.get('sourceurl'), headrev, recurse=False)
+ if server:
+ server_rev = str(server[0][1].rev.number)
except:
self.logger.info("Repository %s does not exist" % entry.get('name'))
return False
+ if entry.get('revision') == 'latest' and cur_rev == server_rev:
+ return True
+
if cur_rev != entry.get('revision'):
self.logger.info("At revision %s need to go to revision %s" %
(cur_rev, entry.get('revision')))