RCF: archive for subrepositories
Martin Geisler
mg at lazybytes.net
Wed Jul 14 14:48:54 CDT 2010
Hi guys,
I've been working on adding support for subrepositories to 'hg archive'.
After some refactoring which I just pushed to crew, these two patches
remain.
Matt suggested on IRC that I add a revision argument to the new subrepo
methods. I think that makes sense so that you can reuse the same subrepo
instance for several things. I can add that in the next iteration.
Having a revision would also make it possible to do
wfiles = sub.files(None)
to get the working copy files, i.e., including files not commited. This
should be useful for addign subrepo support to 'hg add'.
You'll notice that the second adds a test case without an output file,
so this is just to give you something to test with.
Notice also that there is some overlap between abstractsubrepo.archive
and archival.archive. We could get rid of this if we could turn the repo
into a subrepo and just call archive on the subrepo. However, that would
push all the archival logic into the subrepo class which is a bit weird.
# HG changeset patch
# User Martin Geisler <mg at lazybytes.net>
# Date 1279136212 -7200
# Node ID 53c6bad15d208329098eb09c9368e39513dcf8d5
# Parent cd6884231db8affc19e2f8107fd8c65ef60709f3
subrepo: introduce files and filedata methods for subrepo classes
diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py
--- a/mercurial/subrepo.py
+++ b/mercurial/subrepo.py
@@ -213,6 +213,18 @@
"""
raise NotImplementedError
+ def files(self):
+ """return filename iterator"""
+ raise NotImplementedError
+
+ def filedata(self, name):
+ """return file data"""
+ raise NotImplementedError
+
+ def fileflags(self, name):
+ """return file flags"""
+ return ''
+
class hgsubrepo(abstractsubrepo):
def __init__(self, ctx, path, state):
@@ -311,6 +323,20 @@
other = hg.repository(self._repo.ui, dsturl)
return self._repo.push(other, force)
+ def files(self):
+ rev = self._state[1]
+ ctx = self._repo[rev]
+ return list(ctx)
+
+ def filedata(self, name):
+ rev = self._state[1]
+ return self._repo[rev][name].data()
+
+ def fileflags(self, name):
+ rev = self._state[1]
+ ctx = self._repo[rev]
+ return ctx.flags(name)
+
class svnsubrepo(abstractsubrepo):
def __init__(self, ctx, path, state):
self._path = path
@@ -413,6 +439,14 @@
# push is a no-op for SVN
return True
+ def files(self):
+ output = self._svncommand(['list'])
+ # This works because svn forbids \n in filenames.
+ return output.splitlines()
+
+ def filedata(self, name):
+ return self._svncommand(['cat'], name)
+
types = {
'hg': hgsubrepo,
'svn': svnsubrepo,
# HG changeset patch
# User Martin Geisler <mg at lazybytes.net>
# Date 1279136212 -7200
# Node ID f0bf9d7b6cb7e8b8d97c882828669b61a850c60a
# Parent 53c6bad15d208329098eb09c9368e39513dcf8d5
subrepo: add support for 'hg archive'
diff --git a/mercurial/archival.py b/mercurial/archival.py
--- a/mercurial/archival.py
+++ b/mercurial/archival.py
@@ -8,6 +8,7 @@
from i18n import _
from node import hex
import cmdutil
+import subrepo
import util
import cStringIO, os, stat, tarfile, time, zipfile
import zlib, gzip
@@ -256,4 +257,9 @@
for f in ctx:
ff = ctx.flags(f)
write(f, 'x' in ff and 0755 or 0644, 'l' in ff, ctx[f].data)
+
+ for subpath in ctx.substate:
+ s = subrepo.subrepo(ctx, subpath)
+ s.archive(archiver, prefix)
+
archiver.done()
diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py
--- a/mercurial/subrepo.py
+++ b/mercurial/subrepo.py
@@ -225,6 +225,14 @@
"""return file flags"""
return ''
+ def archive(self, archiver, prefix):
+ for name in self.files():
+ flags = self.fileflags(name)
+ mode = 'x' in flags and 0755 or 0644
+ symlink = 'l' in flags
+ archiver.addfile(os.path.join(prefix, self._path, name),
+ mode, symlink, self.filedata(name))
+
class hgsubrepo(abstractsubrepo):
def __init__(self, ctx, path, state):
@@ -255,6 +263,15 @@
addpathconfig('default-push', defpushpath)
fp.close()
+ def archive(self, archiver, prefix):
+ abstractsubrepo.archive(self, archiver, prefix)
+
+ rev = self._state[1]
+ ctx = self._repo[rev]
+ for subpath in ctx.substate:
+ s = subrepo(ctx, subpath)
+ s.archive(archiver, os.path.join(prefix, self._path))
+
def dirty(self):
r = self._state[1]
if r == '':
diff --git a/tests/test-archive-subrepos b/tests/test-archive-subrepos
new file mode 100755
--- /dev/null
+++ b/tests/test-archive-subrepos
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+hg init test
+cd test
+
+hg init sub
+echo 'sub = sub' > .hgsub
+touch a.txt
+hg add
+
+cd sub
+hg init sub-sub
+echo 'sub-sub = sub-sub' > .hgsub
+touch b.txt
+hg add
+
+cd sub-sub
+hg init sub-sub-sub
+echo 'sub-sub-sub = sub-sub-sub' > .hgsub
+touch c.txt
+hg add
+
+cd sub-sub-sub
+touch d.txt
+hg add
+
+cd ../../../
+hg commit -m initialized
+hg archive ../archive
+ls -Ral ../archive
+
+hg archive ../archive.zip
+unzip -l ../archive.zip
--
Martin Geisler
Mercurial links: http://mercurial.ch/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
URL: <http://selenic.com/pipermail/mercurial-devel/attachments/20100714/8e6dae7f/attachment.pgp>
More information about the Mercurial-devel
mailing list