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