Merge lp:~jelmer/brz/export-nested into lp:brz

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/export-nested
Merge into: lp:brz
Diff against target: 573 lines (+166/-73)
13 files modified
breezy/archive/__init__.py (+3/-2)
breezy/archive/tar.py (+27/-21)
breezy/archive/zip.py (+3/-2)
breezy/builtins.py (+5/-2)
breezy/bzr/inventorytree.py (+5/-3)
breezy/bzr/remote.py (+8/-2)
breezy/bzr/workingtree.py (+5/-1)
breezy/export.py (+31/-25)
breezy/git/remote.py (+6/-2)
breezy/git/tree.py (+9/-4)
breezy/tests/blackbox/test_export.py (+17/-0)
breezy/tests/per_tree/test_export.py (+38/-2)
breezy/tree.py (+9/-7)
To merge this branch: bzr merge lp:~jelmer/brz/export-nested
Reviewer Review Type Date Requested Status
Jelmer Vernooij Approve
Review via email: mp+413552@code.launchpad.net

Commit message

Add support for --recurse-nested argument to 'brz export'.

Description of the change

Add support for --recurse-nested argument to 'brz export'.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/archive/__init__.py'
2--- breezy/archive/__init__.py 2020-02-18 01:57:45 +0000
3+++ breezy/archive/__init__.py 2022-01-03 23:15:42 +0000
4@@ -77,13 +77,14 @@
5
6
7 def create_archive(format, tree, name, root=None, subdir=None,
8- force_mtime=None):
9+ force_mtime=None, recurse_nested=False):
10 try:
11 archive_fn = format_registry.get(format)
12 except KeyError:
13 raise errors.NoSuchExportFormat(format)
14 return archive_fn(tree, name, root=root, subdir=subdir,
15- force_mtime=force_mtime)
16+ force_mtime=force_mtime,
17+ recurse_nested=recurse_nested)
18
19
20 format_registry = ArchiveFormatRegistry()
21
22=== modified file 'breezy/archive/tar.py'
23--- breezy/archive/tar.py 2020-02-18 01:57:45 +0000
24+++ breezy/archive/tar.py 2022-01-03 23:15:42 +0000
25@@ -79,21 +79,20 @@
26 return (item, fileobj)
27
28
29-def tarball_generator(tree, root, subdir=None, force_mtime=None, format=''):
30+def tarball_generator(tree, root, subdir=None, force_mtime=None, format='', recurse_nested=False):
31 """Export tree contents to a tarball.
32
33- :returns: A generator that will produce file content chunks.
34-
35- :param tree: Tree to export
36-
37- :param subdir: Sub directory to export
38-
39- :param force_mtime: Option mtime to force, instead of using tree
40+ Args:
41+ tree: Tree to export
42+ subdir: Sub directory to export
43+ force_mtime: Option mtime to force, instead of using tree
44 timestamps.
45+ Returns: A generator that will produce file content chunks.
46 """
47 buf = BytesIO()
48 with closing(tarfile.open(None, "w:%s" % format, buf)) as ball, tree.lock_read():
49- for final_path, tree_path, entry in _export_iter_entries(tree, subdir):
50+ for final_path, tree_path, entry in _export_iter_entries(
51+ tree, subdir, recurse_nested=recurse_nested):
52 (item, fileobj) = prepare_tarball_item(
53 tree, root, final_path, tree_path, entry, force_mtime)
54 ball.addfile(item, fileobj)
55@@ -104,7 +103,7 @@
56 yield buf.getvalue()
57
58
59-def tgz_generator(tree, dest, root, subdir, force_mtime=None):
60+def tgz_generator(tree, dest, root, subdir, force_mtime=None, recurse_nested=False):
61 """Export this tree to a new tar file.
62
63 `dest` will be created holding the contents of this tree; if it
64@@ -133,7 +132,9 @@
65 buf = BytesIO()
66 zipstream = gzip.GzipFile(basename, 'w', fileobj=buf,
67 mtime=root_mtime)
68- for chunk in tarball_generator(tree, root, subdir, force_mtime):
69+ for chunk in tarball_generator(
70+ tree, root, subdir, force_mtime,
71+ recurse_nested=recurse_nested):
72 zipstream.write(chunk)
73 # Yield the data that was written so far, rinse, repeat.
74 yield buf.getvalue()
75@@ -144,33 +145,37 @@
76 yield buf.getvalue()
77
78
79-def tbz_generator(tree, dest, root, subdir, force_mtime=None):
80+def tbz_generator(tree, dest, root, subdir, force_mtime=None, recurse_nested=False):
81 """Export this tree to a new tar file.
82
83 `dest` will be created holding the contents of this tree; if it
84 already exists, it will be clobbered, like with "tar -c".
85 """
86 return tarball_generator(
87- tree, root, subdir, force_mtime, format='bz2')
88+ tree, root, subdir, force_mtime, format='bz2',
89+ recurse_nested=recurse_nested)
90
91
92 def plain_tar_generator(tree, dest, root, subdir,
93- force_mtime=None):
94+ force_mtime=None, recurse_nested=False):
95 """Export this tree to a new tar file.
96
97 `dest` will be created holding the contents of this tree; if it
98 already exists, it will be clobbered, like with "tar -c".
99 """
100 return tarball_generator(
101- tree, root, subdir, force_mtime, format='')
102-
103-
104-def tar_xz_generator(tree, dest, root, subdir, force_mtime=None):
105- return tar_lzma_generator(tree, dest, root, subdir, force_mtime, "xz")
106+ tree, root, subdir, force_mtime, format='',
107+ recurse_nested=recurse_nested)
108+
109+
110+def tar_xz_generator(tree, dest, root, subdir, force_mtime=None, recurse_nested=False):
111+ return tar_lzma_generator(
112+ tree, dest, root, subdir, force_mtime, "xz",
113+ recurse_nested=recurse_nested)
114
115
116 def tar_lzma_generator(tree, dest, root, subdir, force_mtime=None,
117- compression_format="alone"):
118+ compression_format="alone", recurse_nested=False):
119 """Export this tree to a new .tar.lzma file.
120
121 `dest` will be created holding the contents of this tree; if it
122@@ -189,7 +194,8 @@
123 }[compression_format])
124
125 for chunk in tarball_generator(
126- tree, root, subdir, force_mtime=force_mtime):
127+ tree, root, subdir, force_mtime=force_mtime,
128+ recurse_nested=recurse_nested):
129 yield compressor.compress(chunk)
130
131 yield compressor.flush()
132
133=== modified file 'breezy/archive/zip.py'
134--- breezy/archive/zip.py 2020-02-18 01:57:45 +0000
135+++ breezy/archive/zip.py 2022-01-03 23:15:42 +0000
136@@ -43,7 +43,7 @@
137
138
139 def zip_archive_generator(tree, dest, root, subdir=None,
140- force_mtime=None):
141+ force_mtime=None, recurse_nested=False):
142 """ Export this tree to a new zip file.
143
144 `dest` will be created holding the contents of this tree; if it
145@@ -53,7 +53,8 @@
146 with tempfile.SpooledTemporaryFile() as buf:
147 with closing(zipfile.ZipFile(buf, "w", compression)) as zipf, \
148 tree.lock_read():
149- for dp, tp, ie in _export_iter_entries(tree, subdir):
150+ for dp, tp, ie in _export_iter_entries(
151+ tree, subdir, recurse_nested=recurse_nested):
152 mutter(" export {%s} kind %s to %s", tp, ie.kind, dest)
153
154 # zipfile.ZipFile switches all paths to forward
155
156=== modified file 'breezy/builtins.py'
157--- breezy/builtins.py 2021-12-20 23:40:21 +0000
158+++ breezy/builtins.py 2022-01-03 23:15:42 +0000
159@@ -3368,11 +3368,13 @@
160 Option('uncommitted',
161 help='Export the working tree contents rather than that of the '
162 'last revision.'),
163+ Option('recurse-nested',
164+ help='Include contents of nested trees.'),
165 ]
166
167 def run(self, dest, branch_or_subdir=None, revision=None, format=None,
168 root=None, filters=False, per_file_timestamps=False, uncommitted=False,
169- directory=u'.'):
170+ directory=u'.', recurse_nested=False):
171 from .export import export, guess_format, get_root_name
172
173 if branch_or_subdir is None:
174@@ -3411,7 +3413,8 @@
175
176 try:
177 export(export_tree, dest, format, root, subdir,
178- per_file_timestamps=per_file_timestamps)
179+ per_file_timestamps=per_file_timestamps,
180+ recurse_nested=recurse_nested)
181 except errors.NoSuchExportFormat as e:
182 raise errors.CommandError(
183 gettext('Unsupported export format: %s') % e.format)
184
185=== modified file 'breezy/bzr/inventorytree.py'
186--- breezy/bzr/inventorytree.py 2021-12-25 12:35:22 +0000
187+++ breezy/bzr/inventorytree.py 2022-01-03 23:15:42 +0000
188@@ -302,9 +302,11 @@
189 def iter_entries(inv):
190 for p, e in inv.iter_entries_by_dir(specific_file_ids=inventory_file_ids):
191 if e.kind == 'tree-reference' and recurse_nested:
192- subinv = self._get_nested_tree(p, e.file_id, e.reference_revision).root_inventory
193- for subp, e in iter_entries(subinv):
194- yield (osutils.pathjoin(p, subp) if subp else p), e
195+ subtree = self._get_nested_tree(p, e.file_id, e.reference_revision)
196+ with subtree.lock_read():
197+ subinv = subtree.root_inventory
198+ for subp, e in iter_entries(subinv):
199+ yield (osutils.pathjoin(p, subp) if subp else p), e
200 else:
201 yield p, e
202 return iter_entries(self.root_inventory)
203
204=== modified file 'breezy/bzr/remote.py'
205--- breezy/bzr/remote.py 2021-08-18 22:38:08 +0000
206+++ breezy/bzr/remote.py 2022-01-03 23:15:42 +0000
207@@ -962,13 +962,19 @@
208 def __init__(self, repository, inv, revision_id):
209 super(RemoteInventoryTree, self).__init__(repository, inv, revision_id)
210
211- def archive(self, format, name, root=None, subdir=None, force_mtime=None):
212+ def archive(self, format, name, root=None, subdir=None, force_mtime=None, recurse_nested=False):
213+ if recurse_nested:
214+ # For now, just fall back to non-HPSS mode if nested trees are involved.
215+ return super(RemoteInventoryTree, self).archive(
216+ format, name, root, subdir, force_mtime=force_mtime,
217+ recurse_nested=recurse_nested)
218 ret = self._repository._revision_archive(
219 self.get_revision_id(), format, name, root, subdir,
220 force_mtime=force_mtime)
221 if ret is None:
222 return super(RemoteInventoryTree, self).archive(
223- format, name, root, subdir, force_mtime=force_mtime)
224+ format, name, root, subdir, force_mtime=force_mtime,
225+ recurse_nested=recurse_nested)
226 return ret
227
228 def annotate_iter(self, path,
229
230=== modified file 'breezy/bzr/workingtree.py'
231--- breezy/bzr/workingtree.py 2021-11-13 13:01:39 +0000
232+++ breezy/bzr/workingtree.py 2022-01-03 23:15:42 +0000
233@@ -73,6 +73,7 @@
234 errors,
235 osutils,
236 )
237+from ..controldir import ControlDir
238 from ..lock import LogicalLockResult
239 from .inventorytree import InventoryRevisionTree, MutableInventoryTree
240 from ..trace import mutter, note
241@@ -509,6 +510,9 @@
242 def get_nested_tree(self, path):
243 return WorkingTree.open(self.abspath(path))
244
245+ def _get_nested_tree(self, path, file_id, reference_revision):
246+ return self.get_nested_tree(path)
247+
248 def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
249 """See MutableTree.set_parent_trees."""
250 parent_ids = [rev for (rev, tree) in parents_list]
251@@ -1756,7 +1760,7 @@
252 # The only trick here is that if we supports_tree_reference then we
253 # need to detect if a directory becomes a tree-reference.
254 iterator = super(WorkingTree, self).iter_entries_by_dir(
255- specific_files=specific_files)
256+ specific_files=specific_files, recurse_nested=recurse_nested)
257 if not self.supports_tree_reference():
258 return iterator
259 else:
260
261=== modified file 'breezy/export.py'
262--- breezy/export.py 2022-01-03 13:33:13 +0000
263+++ breezy/export.py 2022-01-03 23:15:42 +0000
264@@ -31,27 +31,29 @@
265
266
267 def export(tree, dest, format=None, root=None, subdir=None,
268- per_file_timestamps=False, fileobj=None):
269+ per_file_timestamps=False, fileobj=None,
270+ recurse_nested=False):
271 """Export the given Tree to the specific destination.
272
273- :param tree: A Tree (such as RevisionTree) to export
274- :param dest: The destination where the files,etc should be put
275- :param format: The format (dir, zip, etc), if None, it will check the
276- extension on dest, looking for a match
277- :param root: The root location inside the format.
278- It is common practise to have zipfiles and tarballs
279- extract into a subdirectory, rather than into the
280- current working directory.
281- If root is None, the default root will be
282- selected as the destination without its
283- extension.
284- :param subdir: A starting directory within the tree. None means to export
285- the entire tree, and anything else should specify the relative path to
286- a directory to start exporting from.
287- :param per_file_timestamps: Whether to use the timestamp stored in the
288- tree rather than now(). This will do a revision lookup
289- for every file so will be significantly slower.
290- :param fileobj: Optional file object to use
291+ Args:
292+ tree: A Tree (such as RevisionTree) to export
293+ dest: The destination where the files,etc should be put
294+ format: The format (dir, zip, etc), if None, it will check the
295+ extension on dest, looking for a match
296+ root: The root location inside the format.
297+ It is common practise to have zipfiles and tarballs
298+ extract into a subdirectory, rather than into the
299+ current working directory.
300+ If root is None, the default root will be
301+ selected as the destination without its
302+ extension.
303+ subdir: A starting directory within the tree. None means to export the
304+ entire tree, and anything else should specify the relative path
305+ to a directory to start exporting from.
306+ per_file_timestamps: Whether to use the timestamp stored in the tree
307+ rather than now(). This will do a revision lookup for every file so will
308+ be significantly slower.
309+ fileobj: Optional file object to use
310 """
311 if format is None and dest is not None:
312 format = guess_format(dest)
313@@ -79,13 +81,15 @@
314 # then we should stream a tar file and unpack that on the fly.
315 with tree.lock_read():
316 for unused in dir_exporter_generator(tree, dest, root, subdir,
317- force_mtime):
318+ force_mtime,
319+ recurse_nested=recurse_nested):
320 pass
321 return
322
323 with tree.lock_read():
324 chunks = tree.archive(format, dest, root=root,
325- subdir=subdir, force_mtime=force_mtime)
326+ subdir=subdir, force_mtime=force_mtime,
327+ recurse_nested=recurse_nested)
328 if dest == '-':
329 for chunk in chunks:
330 getattr(sys.stdout, 'buffer', sys.stdout).write(chunk)
331@@ -126,7 +130,7 @@
332 return dest
333
334
335-def _export_iter_entries(tree, subdir, skip_special=True):
336+def _export_iter_entries(tree, subdir, skip_special=True, recurse_nested=False):
337 """Iter the entries for tree suitable for exporting.
338
339 :param tree: A tree object.
340@@ -139,7 +143,7 @@
341 subdir = None
342 if subdir is not None:
343 subdir = subdir.rstrip('/')
344- entries = tree.iter_entries_by_dir()
345+ entries = tree.iter_entries_by_dir(recurse_nested=recurse_nested)
346 for path, entry in entries:
347 if path == '':
348 continue
349@@ -166,7 +170,8 @@
350
351
352 def dir_exporter_generator(tree, dest, root, subdir=None,
353- force_mtime=None, fileobj=None):
354+ force_mtime=None, fileobj=None,
355+ recurse_nested=False):
356 """Return a generator that exports this tree to a new directory.
357
358 `dest` should either not exist or should be empty. If it does not exist it
359@@ -192,7 +197,8 @@
360 # Note in the case of revision trees, this does trigger a double inventory
361 # lookup, hopefully it isn't too expensive.
362 to_fetch = []
363- for dp, tp, ie in _export_iter_entries(tree, subdir):
364+ for dp, tp, ie in _export_iter_entries(
365+ tree, subdir, recurse_nested=recurse_nested):
366 fullpath = osutils.pathjoin(dest, dp)
367 if ie.kind == "file":
368 to_fetch.append((tp, (dp, tp, None)))
369
370=== modified file 'breezy/git/remote.py'
371--- breezy/git/remote.py 2021-11-13 13:27:11 +0000
372+++ breezy/git/remote.py 2022-01-03 23:15:42 +0000
373@@ -421,7 +421,9 @@
374 return RemoteGitRepository
375
376 def archive(self, format, committish, write_data, progress=None,
377- write_error=None, subdirs=None, prefix=None):
378+ write_error=None, subdirs=None, prefix=None, recurse_nested=False):
379+ if recurse_nested:
380+ raise NotImplementedError('recurse_nested is not yet supported')
381 if progress is None:
382 pb = ui.ui_factory.nested_progress_bar()
383 progress = DefaultProgressReporter(pb).progress
384@@ -882,7 +884,7 @@
385
386 class GitRemoteRevisionTree(RevisionTree):
387
388- def archive(self, format, name, root=None, subdir=None, force_mtime=None):
389+ def archive(self, format, name, root=None, subdir=None, force_mtime=None, recurse_nested=False):
390 """Create an archive of this tree.
391
392 :param format: Format name (e.g. 'tar')
393@@ -891,6 +893,8 @@
394 :param subdir: Subdirectory to export (or None)
395 :return: Iterator over archive chunks
396 """
397+ if recurse_nested:
398+ raise NotImplementedError('recurse_nested is not yet supported')
399 commit = self._repository.lookup_bzr_revision_id(
400 self.get_revision_id())[0]
401 import tempfile
402
403=== modified file 'breezy/git/tree.py'
404--- breezy/git/tree.py 2021-12-25 12:35:22 +0000
405+++ breezy/git/tree.py 2022-01-03 23:15:42 +0000
406@@ -351,6 +351,9 @@
407 else:
408 nested_repo_transport = self._repository.controldir.control_transport.clone(
409 posixpath.join('modules', decode_git_path(info[1])))
410+ if not nested_repo_transport.has('.'):
411+ nested_repo_transport = self._repository.controldir.user_transport.clone(
412+ posixpath.join(decode_git_path(info[1]), '.git'))
413 nested_controldir = _mod_controldir.ControlDir.open_from_transport(
414 nested_repo_transport)
415 return nested_controldir.find_repository()
416@@ -574,14 +577,16 @@
417 child_path_decoded = decode_git_path(child_path)
418 if recurse_nested and S_ISGITLINK(mode):
419 mode = stat.S_IFDIR
420- store = self._get_submodule_store(child_path)
421- hexsha = store[hexsha].tree
422+ substore = self._get_submodule_store(child_path)
423+ hexsha = substore[hexsha].tree
424+ else:
425+ substore = store
426 if stat.S_ISDIR(mode):
427 if (specific_files is None or
428 any([p for p in specific_files if p.startswith(
429 child_path)])):
430 extradirs.append(
431- (store, child_path, hexsha,
432+ (substore, child_path, hexsha,
433 self.path2id(child_path_decoded)))
434 if specific_files is None or child_path in specific_files:
435 if stat.S_ISDIR(mode):
436@@ -589,7 +594,7 @@
437 self._get_dir_ie(child_path, parent_id))
438 else:
439 yield (child_path_decoded,
440- self._get_file_ie(store, child_path, name, mode,
441+ self._get_file_ie(substore, child_path, name, mode,
442 hexsha, parent_id))
443 todo.extendleft(reversed(extradirs))
444
445
446=== modified file 'breezy/tests/blackbox/test_export.py'
447--- breezy/tests/blackbox/test_export.py 2020-06-19 21:26:53 +0000
448+++ breezy/tests/blackbox/test_export.py 2022-01-03 23:15:42 +0000
449@@ -241,6 +241,23 @@
450 d_info = zfile.getinfo(names[3])
451 self.assertEqual(dir_attr, d_info.external_attr)
452
453+ def test_dir_export_nested(self):
454+ tree = self.make_branch_and_tree('dir')
455+ self.build_tree(['dir/a'])
456+ tree.add('a')
457+
458+ subtree = self.make_branch_and_tree('dir/subdir')
459+ tree.add_reference(subtree)
460+
461+ self.build_tree(['dir/subdir/b'])
462+ subtree.add('b')
463+
464+ self.run_bzr('export --uncommitted direxport1 dir')
465+ self.assertFalse(os.path.exists('direxport1/subdir/b'))
466+
467+ self.run_bzr('export --recurse-nested --uncommitted direxport2 dir')
468+ self.assertTrue(os.path.exists('direxport2/subdir/b'))
469+
470 def test_dir_export(self):
471 tree = self.make_branch_and_tree('dir')
472 self.build_tree(['dir/a'])
473
474=== modified file 'breezy/tests/per_tree/test_export.py'
475--- breezy/tests/per_tree/test_export.py 2021-12-08 18:46:11 +0000
476+++ breezy/tests/per_tree/test_export.py 2022-01-03 23:15:42 +0000
477@@ -18,12 +18,14 @@
478 import tarfile
479 import zipfile
480
481+from breezy.errors import UnsupportedOperation
482 from breezy.export import export
483 from breezy import osutils
484 from breezy import tests
485 from breezy.tests.per_tree import TestCaseWithTree
486 from breezy.tests import (
487 features,
488+ TestNotApplicable,
489 )
490
491
492@@ -59,6 +61,35 @@
493 names = self.get_export_names()
494 self.assertIn('output/link', names)
495
496+ def prepare_nested_export(self, recurse_nested):
497+ tree = self.make_branch_and_tree('dir')
498+ self.build_tree(['dir/a'])
499+ tree.add('a')
500+ tree.commit('1')
501+
502+ subtree = self.make_branch_and_tree('dir/subdir')
503+
504+ self.build_tree(['dir/subdir/b'])
505+ subtree.add('b')
506+ subtree.commit('1a')
507+
508+ try:
509+ tree.add_reference(subtree)
510+ except UnsupportedOperation:
511+ raise TestNotApplicable('format does not supported nested trees')
512+ tree.commit('2')
513+ export(tree, 'output', self.exporter, recurse_nested=recurse_nested)
514+
515+ def test_export_nested_recurse(self):
516+ self.prepare_nested_export(True)
517+ names = self.get_export_names()
518+ self.assertIn('output/subdir/b', names)
519+
520+ def test_export_nested_nonrecurse(self):
521+ self.prepare_nested_export(False)
522+ names = self.get_export_names()
523+ self.assertNotIn('output/subdir/b', names)
524+
525
526 class TestTar(ExportTest, TestCaseWithTree):
527
528@@ -94,5 +125,10 @@
529 exporter = 'dir'
530
531 def get_export_names(self):
532- return [osutils.pathjoin('output', name)
533- for name in os.listdir('output')]
534+ ret = []
535+ for (dirpath, dirnames, filenames) in os.walk('output'):
536+ for dirname in dirnames:
537+ ret.append(osutils.pathjoin(dirpath, dirname))
538+ for filename in filenames:
539+ ret.append(osutils.pathjoin(dirpath, filename))
540+ return ret
541
542=== modified file 'breezy/tree.py'
543--- breezy/tree.py 2021-12-25 12:35:22 +0000
544+++ breezy/tree.py 2022-01-03 23:15:42 +0000
545@@ -713,19 +713,21 @@
546 return searcher
547
548 def archive(self, format, name, root='', subdir=None,
549- force_mtime=None):
550+ force_mtime=None, recurse_nested=False):
551 """Create an archive of this tree.
552
553- :param format: Format name (e.g. 'tar')
554- :param name: target file name
555- :param root: Root directory name (or None)
556- :param subdir: Subdirectory to export (or None)
557- :return: Iterator over archive chunks
558+ Args:
559+ format: Format name (e.g. 'tar')
560+ name: target file name
561+ root: Root directory name (or None)
562+ subdir: Subdirectory to export (or None)
563+ Returns: Iterator over archive chunks
564 """
565 from .archive import create_archive
566 with self.lock_read():
567 return create_archive(format, self, name, root,
568- subdir, force_mtime=force_mtime)
569+ subdir, force_mtime=force_mtime,
570+ recurse_nested=recurse_nested)
571
572 @classmethod
573 def versionable_kind(cls, kind):

Subscribers

People subscribed via source and target branches