Add linkfile support.

It's just like copyfile and runs at the same time as copyfile but
instead of copying it creates a symlink instead.  This is needed
because copyfile copies the target of the link as opposed to the
symlink itself.

Change-Id: I7bff2aa23f0d80d9d51061045bd9c86a9b741ac5
This commit is contained in:
Jeff Hamilton 2014-04-21 17:10:59 -05:00
parent 5a7c3afa73
commit e0df232da7
2 changed files with 57 additions and 8 deletions

View File

@ -261,6 +261,12 @@ class XmlManifest(object):
ce.setAttribute('dest', c.dest) ce.setAttribute('dest', c.dest)
e.appendChild(ce) e.appendChild(ce)
for l in p.linkfiles:
le = doc.createElement('linkfile')
le.setAttribute('src', l.src)
le.setAttribute('dest', l.dest)
e.appendChild(le)
default_groups = ['all', 'name:%s' % p.name, 'path:%s' % p.relpath] default_groups = ['all', 'name:%s' % p.name, 'path:%s' % p.relpath]
egroups = [g for g in p.groups if g not in default_groups] egroups = [g for g in p.groups if g not in default_groups]
if egroups: if egroups:
@ -765,6 +771,8 @@ class XmlManifest(object):
for n in node.childNodes: for n in node.childNodes:
if n.nodeName == 'copyfile': if n.nodeName == 'copyfile':
self._ParseCopyFile(project, n) self._ParseCopyFile(project, n)
if n.nodeName == 'linkfile':
self._ParseLinkFile(project, n)
if n.nodeName == 'annotation': if n.nodeName == 'annotation':
self._ParseAnnotation(project, n) self._ParseAnnotation(project, n)
if n.nodeName == 'project': if n.nodeName == 'project':
@ -814,6 +822,14 @@ class XmlManifest(object):
# dest is relative to the top of the tree # dest is relative to the top of the tree
project.AddCopyFile(src, dest, os.path.join(self.topdir, dest)) project.AddCopyFile(src, dest, os.path.join(self.topdir, dest))
def _ParseLinkFile(self, project, node):
src = self._reqatt(node, 'src')
dest = self._reqatt(node, 'dest')
if not self.IsMirror:
# src is project relative;
# dest is relative to the top of the tree
project.AddLinkFile(src, dest, os.path.join(self.topdir, dest))
def _ParseAnnotation(self, project, node): def _ParseAnnotation(self, project, node):
name = self._reqatt(node, 'name') name = self._reqatt(node, 'name')
value = self._reqatt(node, 'value') value = self._reqatt(node, 'value')

View File

@ -231,6 +231,30 @@ class _CopyFile:
except IOError: except IOError:
_error('Cannot copy file %s to %s', src, dest) _error('Cannot copy file %s to %s', src, dest)
class _LinkFile:
def __init__(self, src, dest, abssrc, absdest):
self.src = src
self.dest = dest
self.abs_src = abssrc
self.abs_dest = absdest
def _Link(self):
src = self.abs_src
dest = self.abs_dest
# link file if it does not exist or is out of date
if not os.path.islink(dest) or os.readlink(dest) != src:
try:
# remove existing file first, since it might be read-only
if os.path.exists(dest):
os.remove(dest)
else:
dest_dir = os.path.dirname(dest)
if not os.path.isdir(dest_dir):
os.makedirs(dest_dir)
os.symlink(src, dest)
except IOError:
_error('Cannot link file %s to %s', src, dest)
class RemoteSpec(object): class RemoteSpec(object):
def __init__(self, def __init__(self,
name, name,
@ -555,6 +579,7 @@ class Project(object):
self.snapshots = {} self.snapshots = {}
self.copyfiles = [] self.copyfiles = []
self.linkfiles = []
self.annotations = [] self.annotations = []
self.config = GitConfig.ForRepository( self.config = GitConfig.ForRepository(
gitdir = self.gitdir, gitdir = self.gitdir,
@ -1040,7 +1065,7 @@ class Project(object):
except OSError as e: except OSError as e:
print("warn: Cannot remove archive %s: " print("warn: Cannot remove archive %s: "
"%s" % (tarpath, str(e)), file=sys.stderr) "%s" % (tarpath, str(e)), file=sys.stderr)
self._CopyFiles() self._CopyAndLinkFiles()
return True return True
if is_new is None: if is_new is None:
@ -1103,9 +1128,11 @@ class Project(object):
def PostRepoUpgrade(self): def PostRepoUpgrade(self):
self._InitHooks() self._InitHooks()
def _CopyFiles(self): def _CopyAndLinkFiles(self):
for copyfile in self.copyfiles: for copyfile in self.copyfiles:
copyfile._Copy() copyfile._Copy()
for linkfile in self.linkfiles:
linkfile._Link()
def GetCommitRevisionId(self): def GetCommitRevisionId(self):
"""Get revisionId of a commit. """Get revisionId of a commit.
@ -1152,7 +1179,7 @@ class Project(object):
def _doff(): def _doff():
self._FastForward(revid) self._FastForward(revid)
self._CopyFiles() self._CopyAndLinkFiles()
head = self.work_git.GetHead() head = self.work_git.GetHead()
if head.startswith(R_HEADS): if head.startswith(R_HEADS):
@ -1188,7 +1215,7 @@ class Project(object):
except GitError as e: except GitError as e:
syncbuf.fail(self, e) syncbuf.fail(self, e)
return return
self._CopyFiles() self._CopyAndLinkFiles()
return return
if head == revid: if head == revid:
@ -1210,7 +1237,7 @@ class Project(object):
except GitError as e: except GitError as e:
syncbuf.fail(self, e) syncbuf.fail(self, e)
return return
self._CopyFiles() self._CopyAndLinkFiles()
return return
upstream_gain = self._revlist(not_rev(HEAD), revid) upstream_gain = self._revlist(not_rev(HEAD), revid)
@ -1283,12 +1310,12 @@ class Project(object):
if cnt_mine > 0 and self.rebase: if cnt_mine > 0 and self.rebase:
def _dorebase(): def _dorebase():
self._Rebase(upstream = '%s^1' % last_mine, onto = revid) self._Rebase(upstream = '%s^1' % last_mine, onto = revid)
self._CopyFiles() self._CopyAndLinkFiles()
syncbuf.later2(self, _dorebase) syncbuf.later2(self, _dorebase)
elif local_changes: elif local_changes:
try: try:
self._ResetHard(revid) self._ResetHard(revid)
self._CopyFiles() self._CopyAndLinkFiles()
except GitError as e: except GitError as e:
syncbuf.fail(self, e) syncbuf.fail(self, e)
return return
@ -1301,6 +1328,12 @@ class Project(object):
abssrc = os.path.join(self.worktree, src) abssrc = os.path.join(self.worktree, src)
self.copyfiles.append(_CopyFile(src, dest, abssrc, absdest)) self.copyfiles.append(_CopyFile(src, dest, abssrc, absdest))
def AddLinkFile(self, src, dest, absdest):
# dest should already be an absolute path, but src is project relative
# make src an absolute path
abssrc = os.path.join(self.worktree, src)
self.linkfiles.append(_LinkFile(src, dest, abssrc, absdest))
def AddAnnotation(self, name, value, keep): def AddAnnotation(self, name, value, keep):
self.annotations.append(_Annotation(name, value, keep)) self.annotations.append(_Annotation(name, value, keep))
@ -2195,7 +2228,7 @@ class Project(object):
if GitCommand(self, cmd).Wait() != 0: if GitCommand(self, cmd).Wait() != 0:
raise GitError("cannot initialize work tree") raise GitError("cannot initialize work tree")
self._CopyFiles() self._CopyAndLinkFiles()
def _gitdir_path(self, path): def _gitdir_path(self, path):
return os.path.realpath(os.path.join(self.gitdir, path)) return os.path.realpath(os.path.join(self.gitdir, path))