1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """
19 Internal module providing top-level pybaz package names
20
21 This module implements the top-level public interface for the
22 pybaz_ package. But for convenience reasons the author prefers
23 to store this code in a file separate from ``__init__.py``.
24
25 .. _pybaz: pybaz-module.html
26
27 This module is strictly internal and should never be used.
28
29 :var backend: See `pybaz.backend`
30
31 :var _arch: Internal deprecated interface to the backend
32 """
33
34
35
36 import os
37 import shutil
38 import itertools
39 import re
40 from sets import ImmutableSet
41 import errors
42 import util
43 from pathname import PathName, FileName, DirName
44 from deprecation import deprecated_usage, deprecated_callable
45 from _escaping import *
46 from _output import *
47 from _location import *
48
49 __all__ = []
50
53
54
55
56
58 """Internal hack for compatibility with _arch"""
63
64 _arch = _BackendProxy()
65
66 from backends import commandline
67
68 backend = commandline.default_backend()
69
70 public('backend')
71
72
73
74
75 public('Factory', 'factory')
76
78 if not isinstance(value, type):
79 if type.__module__ == '__builtin__':
80 typename = type.__name__
81 else:
82 typename = type.__module__ + '.' + type.__name__
83 raise TypeError("%s must be a %s, but was: %r"
84 % (name, typename, value))
85
86
88
89 """Abstract factory for objects created by the public interface.
90
91 Eventually, it will possible to alter the type all objects created by
92 PyBaz, system-wide (by assigning to `pybaz.factory`) or locally (by using a
93 factory attribute in instances).
94
95 Currently, this is only used internally to localise the cyclic dependencies
96 between various internal modules.
97 """
98
100 """Create an Archive.
101
102 :param name: archive name
103 :type name: str
104 :rtype: `Archive`
105 """
106 _check_param_type('name', name, str)
107 return Archive(name)
108
110 """Does the object implement the Archive interface?
111
112 :rtype: bool
113 """
114 return isinstance(obj, Archive)
115
117 """Create a Version.
118
119 :param name: fully qualified name of the version.
120 :type name: str
121 :rtype: `Version`
122 """
123 _check_param_type('name', name, str)
124 return Version(name)
125
127 """Does the object implement the Version interface?
128
129 :rtype: bool
130 """
131 return isinstance(obj, Version)
132
134 """Create a Revision.
135
136 :param name: fully qualified name of the revision
137 :type name: str
138 :rtype: `Revision`
139 """
140 _check_param_type('name', name, str)
141 return Revision(name)
142
144 """Does the object implement the Revision interface?
145
146 :rtype: bool
147 """
148 return isinstance(obj, Revision)
149
151 """Does the object implement the SourceTree interface?
152
153 :rtype: bool
154 """
155 return isinstance(obj, ArchSourceTree)
156
158 """Create an ArchiveLocation.
159
160 :type url: str
161 """
162 _check_param_type('url', url, str)
163 return ArchiveLocation(url)
164
166 """Does the object implement the ArchiveLocation interface?
167
168 :rtype: bool
169 """
170 return isinstance(obj, ArchiveLocation)
171
172
173 factory = Factory()
174
175
176
177
179 """Used internally to disable namespace sanity checks"""
180
181
190
200
210
221
232
234 """Internal argument checking utility"""
235 if not isinstance(param, Version):
236 raise TypeError("Parameter \"%r\" must be a Version, but was: %r" \
237 % (name, param))
238
240 """Internal argument checking utility"""
241 if not isinstance(param, Revision):
242 raise TypeError("Parameter \"%s\" must be a Revision"
243 " but was: %r" % (name, param))
244
245
246
247
248 public('NamespaceObject')
249
251
252 """Base class for all archive objects."""
253
255 """Deprecated
256
257 Fully qualified name of this namespace object.
258
259 :rtype: str
260 :see: `NamespaceObject.fullname`
261 """
262 raise NotImplementedError
263
264 fullname = property(get_fullname, doc = """
265 Fully qualfied name of this namespace object.
266
267 :type: str
268 """)
269
271 """Does this namespace exists?
272
273 Within the Arch model, history cannot be changed: created archive
274 entries cannot be deleted. However, it is possible to ``unregister`` an
275 archive, or to find references to archives whose location is not known.
276 Thus, existence cannot always be decided. Testing for the existence of
277 a name in a non-registered archive raises
278 `errors.ArchiveNotRegistered`.
279
280 :return: whether this namespace object exists.
281 :rtype: bool
282 :raise errors.ArchiveNotRegistered: the archive name is not registered,
283 so existence cannot be decided.
284 :raise errors.ExecProblem: there was a problem accessing the archive.
285 """
286 raise NotImplementedError
287
289 """Fully-qualified name in angle brackets.
290
291 :rtype: str
292 """
293 return '%s.%s(%r)' % (
294 self.__class__.__module__, self.__class__.__name__, self.fullname)
295
297 """Fully-qualified name.
298
299 Returns the value of the fullname attribute.
300
301 :rtype: str
302 """
303 return self.fullname
304
306 """Compare types and fully-qualified names.
307
308 :return: wether objects have the same types and names.
309 :rtype: bool
310 """
311 return type(self) is type(x) \
312 and self.__class__ is x.__class__ \
313 and self.fullname == x.fullname
314
316 """Compare types and fully-qualified names.
317
318 :return: whether objects have different types or names.
319 :rtype: bool
320 """
321 return type(self) is not type(x) \
322 or self.__class__ is not x.__class__ \
323 or self.fullname != x.fullname
324
325
326
327
328 public(
329 'RevisionIterable',
330 'VersionIterable',
331 'BranchIterable',
332 'CategoryIterable',
333 )
334
336
337 """Abstract class for namespace classes above Revision.
338
339 RevisionIterable provides features which are common to all objects
340 containing revisions.
341 """
342
344 """Iterate over archive revisions.
345
346 :param reverse: reverse order, recent revisions first.
347 :type reverse: bool
348 :return: all existing revisions in this namespace.
349 :rtype: iterable of `Revision`
350
351 :precondition: `self.exists()` returns ``True``.
352 """
353 raise NotImplementedError
354
356 """Iterate over library revisions.
357
358 :param reverse: reverse order, recent revisions first.
359 :type reverse: bool
360 :return: revisions in this namespace which are present in the
361 revision library.
362 :rtype: iterable of `Revision`
363 """
364 raise NotImplementedError
365
366
368
369 """Abstract class for archive classes above Version.
370
371 VersionIterable provides features which are common to all objects
372 containing versions.
373 """
374
376 """Iterate over archive versions.
377
378 :param reverse: reverse order, higher versions first.
379 :type reverse: bool
380 :return: all existing versions in this namespace.
381 :rtype: iterable of `Version`
382
383 :precondition: `self.exists()` returns ``True``.
384 """
385 raise NotImplementedError
386
388 """Iterate over library revisions.
389
390 :param reverse: reverse order, higher versions first.
391 :type reverse: bool
392 :return: versions in this namespace which are present in the
393 revision library.
394 :rtype: iterable of `Version`
395 """
396 raise NotImplementedError
397
401
405
406
408
409 """Base class for archive classes above Branch.
410
411 BranchIterable provides features which are common to all objects
412 containing branches.
413 """
414
416 """Iterate over archive branches.
417
418 :return: all existing branches in this namespace.
419 :rtype: iterable of `Branch`
420 :precondition: `self.exists()` returns ``True``.
421 """
422 raise NotImplementedError
423
425 """Iterate over library branches.
426
427 :return: branches in this namespace which are present in the
428 revision library.
429 :rtype: iterable of `Branch`
430 """
431 raise NotImplementedError
432
436
440
441
443
444 """Base class for Archive.
445
446 CategoryIterable provides features for the aspect of Archive wich
447 relates to its containing other archive objects.
448 """
449
451 """Iterate over archive categories.
452
453 :return: all existing categories in this namespace.
454 :rtype: iterable of `Category`
455 :precondition: `self.exists()` returns ``True``.
456 """
457 raise NotImplementedError
458
460 """Iterate over library categories.
461
462 :return: categories in this namespace which are present in the
463 revision library.
464 :rtype: iterable of `Category`
465 """
466 raise NotImplementedError
467
471
475
476
477
478
479 public(
480 'ArchiveItem',
481 'CategoryItem',
482 'BranchItem',
483 'VersionItem',
484 )
485
487
488 """Base class for all archive components classes.
489
490 ArchiveItem provides features common to all objects which are
491 structural components of Archive.
492 """
493
497
499 """Deprecated.
500
501 Archive which contains this namespace object.
502
503 :rtype: `Archive`
504 :see: `ArchiveItem.archive`
505 """
506 deprecated_callable(self.get_archive, (type(self), 'archive'))
507 return self.archive
508
510 return Archive(_unsafe((self._archive,)))
511
512 archive = property(_get_archive, doc="""
513 Archive which contains this namespace object.
514
515 :type: `Archive`
516 """)
517
519 """Deprecated.
520
521 Non-arch part of this namespace name.
522
523 :rtype: str
524 :see: `ArchiveItem.nonarch`
525 """
526 deprecated_callable(self.get_nonarch, (type(self), 'nonarch'))
527 return self.nonarch
528
531
532 nonarch = property(_get_nonarch, doc="""
533 Non-arch part of this namespace name.
534
535 :type: str
536 """)
537
541
543 return '%s/%s' % (self._archive, self._nonarch)
544
545 fullname = property(_get_fullname, doc=NamespaceObject.fullname.__doc__)
546
547
549
550 """Base class for archive classes below Category.
551
552 CategoryItem provides features common to all objects which are
553 structural components of Category.
554 """
555
557 """Deprecated.
558
559 Category which contains this namespace object.
560
561 :rtype: `Category`
562 :see: `CategoryItem.category`
563 """
564 deprecated_callable(self.get_category, (type(self), 'category'))
565 return self.category
566
568 return Category(_unsafe((self._archive, self._nonarch.split('--')[0])))
569
570 category = property(_get_category, doc="""
571 Category which contains this object.
572
573 :type: `Category`
574 """)
575
576
578
579 """Base class for archive classes Version and Revision.
580
581 BranchItem provides features common to all objects which are
582 structural components of Branch.
583 """
584
586 """Deprecated.
587
588 Branch which contains this object.
589
590 :rtype: `Branch`
591 :see: `BranchItem.branch`
592 """
593 deprecated_callable(self.get_branch, (type(self), 'branch'))
594 return self.branch
595
597 assert isinstance(self, Version)
598 package = '--'.join(self._nonarch.split('--')[0:-1])
599 return Branch(_unsafe((self._archive, package)))
600
601 branch = property(_get_branch, doc="""
602 Branch which contains this namespace object.
603
604 :type: `Branch`
605 """)
606
607
609
610 """Base class for Revision.
611
612 VersionItem provides features for the aspect of Revision which
613 relate to its containment within other archive objects.
614 """
615
616 - def __init__(self, archive, version, patchlevel):
619
623
625 assert isinstance(self, Revision)
626 package = '--'.join(self._version.split('--')[0:-1])
627 return Branch(_unsafe((self._archive, package)))
628
629 branch = property(_get_branch, doc=BranchItem.branch.__doc__)
630
632 """Deprecated.
633
634 Version which contains this revision.
635
636 :rtype: `Version`
637 :see: `VersionItem.version`
638 """
639 deprecated_callable(self.get_version, (type(self), 'version'))
640 return self.version
641
643 return Version(_unsafe((self._archive, self._version)))
644
645 version = property(_get_version, doc="""
646 Version which contains this revision.
647
648 :type: `Version`
649 """)
650
652 """Deprecated.
653
654 Patch-level part of this object's name.
655
656 :rtype: str
657 :see: `VersionItem.patchlevel`
658 """
659 deprecated_callable(self.get_patchlevel, (type(self), 'patchlevel'))
660 return self.patchlevel
661
663 return self._patchlevel
664
665 patchlevel = property(_get_patchlevel, doc="""
666 Patch-level part of this object's name.
667
668 :type: str
669 """)
670
671
672
673
674 public('Setupable', 'Package')
675
677
678 """Base class for container archive objects."""
679
681 """Deprecated.
682
683 PyBaz 1.1 and later do archive-setup implicitly.
684 """
685 deprecated_callable(self.setup, because=
686 'pybaz 1.1 and later do archive-setup implicitly.')
687
688
689 -class Package(Setupable, RevisionIterable):
690
691 """Base class for ordered container archive objects."""
692
694 """Deprecated.
695
696 Latest revision in this package.
697
698 :rtype: `Revision`
699 :precondition: `self.exists()` returns ``True``
700 :precondition: `self.iter_revisions()` yields at least one object.
701 :raises StopIteration: this package contains no revision
702 :see: `Package.latest_revision`
703 """
704 deprecated_callable(self.as_revision, self.latest_revision)
705 return self.iter_revisions(reverse=True).next()
706
708 """Latest revision in this package.
709
710 :rtype: `Revision`
711 :precondition: `self.exists()` returns ``True``
712 :precondition: `self.iter_revisions()` yields at least one object.
713 :raises ValueError: the archive is not registered, or this
714 package does not exist, or it contains no revision.
715 """
716 try:
717 return self.iter_revisions(reverse=True).next()
718 except errors.ExecProblem:
719 try:
720 self_exists = self.exists()
721 except errors.ArchiveNotRegistered:
722 raise ValueError('Archive is not registered: %s'
723 % self.archive)
724 if not self_exists:
725 raise ValueError('Package does not exist: %s' % self)
726 raise
727 except StopIteration:
728 raise ValueError('Package contains no revision: %s' % self)
729
730
731
732
733 public('Archive', 'Category', 'Branch', 'Version', 'Revision')
734
735
737
738 """Arch archive namespace object.
739
740 In the Arch revision control system, archives are the units of
741 storage. They store revisions organized in categories, branches
742 and versions, and are associated to a `name` and a `location`.
743
744 :see: `Category`, `Branch`, `Version`, `Revision`
745 """
746
748 """Create an archive object from its registered name.
749
750 :param name: archive name, like "jdoe@example.com--2003"
751 :type name: str
752 :raise errors.NamespaceError: invalid archive name.
753 """
754 if isinstance(name, Archive):
755 name = name.__name
756 if isinstance(name, _unsafe):
757 assert len(name) == 1
758 name = name[0]
759 elif not NameParser.is_archive_name(name):
760 raise errors.NamespaceError(name, 'archive name')
761 self.__name = name
762 self._impl = _archive_impl()
763
774
777
778 name = property(_get_name, doc="""
779 Logical name of the archive.
780
781 :type: str
782 """)
783
787
788 fullname = property(_get_name, doc=NamespaceObject.fullname.__doc__)
789
800
809
810 location = property(_get_location, doc="""
811 Deprecated.
812
813 For example 'http://ddaa.net/arch/2004', or
814 'sftp://user@sourcecontrol.net/public_html/2004'.
815
816 :see: `Archive.all_locations`
817 :type: str
818 """)
819
821 """All registered locations for this archive.
822
823 :rtype: list of `ArchiveLocation`
824 """
825 args = ['whereis-archive', '--all-locations', self.name]
826 try:
827 raw_locations = [factory.ArchiveLocation(url)
828 for url in backend.sequence_cmd(args)]
829 except errors.ExecProblem:
830 if not self.is_registered():
831 return []
832 else:
833 raise
834
835 unique_locations = []
836 for location in raw_locations:
837 if location not in unique_locations:
838 unique_locations.append(location)
839 return unique_locations
840
849
856
868
873
874 is_mirror = property(_get_is_mirror, doc="""
875 Deprecated.
876
877 :see: `ArchiveLocation._meta_info_present`
878 :type: bool
879 """)
880
892
897
898 official_name = property(_get_official_name, doc="""
899 Deprecated.
900
901 :see: `ArchiveLocation._meta_info_present`
902 :type: str
903 """)
904
916
921
922 is_signed = property(_get_is_signed, doc="""
923 Deprecated.
924
925 :see: `ArchiveLocation._meta_info_present`
926 :type: bool
927 """)
928
940
945
946 has_listings = property(_get_has_listings, doc="""
947 Deprecated.
948
949 :see: `ArchiveLocation._meta_info_present`
950 :type: bool
951 """)
952
964
965 version_string = property(_get_version_string, doc="""
966 Deprecated.
967
968 Contents of the ``.archive-version`` file at the root of the archive.
969
970 :see: `ArchiveLocation._version_string`
971 :type: str
972 """)
973
978
982
993
999
1001 """Is this archive registered?
1002
1003 :return: Whether the location associated to this registration name is
1004 known.
1005 :rtype: bool
1006 :see: `register_archive`, `Archive.unregister`
1007 """
1008 for archive in iter_archives():
1009 if archive.name == self.name:
1010 return True
1011 else:
1012 return False
1013
1018
1032
1043
1047
1058
1062
1063 categories = property(_get_categories, doc="""
1064 Deprecated.
1065
1066 Categories in this archive.
1067
1068 :type: tuple of `Category`
1069 :see: `iter_categories`
1070 """)
1071
1083
1088
1089 library_categories = property(_get_library_categories, doc="""
1090 Deprecated.
1091
1092 Categories in this archive present in the library.
1093
1094 :type; tuple of `Category`
1095 :see: `iter_library_categories`
1096 """)
1097
1099 """Unregister this archive.
1100
1101 :precondition: `self.is_registered()`
1102 :postcondition: not `self.is_registered()`
1103 :see: `register_archive`
1104 """
1105 backend.null_cmd(('register-archive', '--delete', self.name))
1106
1107 - def make_mirror(self, name, location, signed=False, listing=False,
1108 tla=False):
1109 """Deprecated.
1110
1111 :see: `ArchiveLocation.create_mirror`
1112
1113 :param name: name of the new mirror (for example
1114 'david@allouche.net--2003b-MIRROR').
1115 :type name: str
1116 :param location: writeable URI were to create the archive mirror.
1117 :type location: str
1118 :param signed: create GPG signatures for the mirror contents
1119 :type signed: bool
1120 :param listing: maintains ''.listing'' files to enable HTTP access.
1121 :type listing: bool
1122 :param tla: create a tla archive instead of a baz archive.
1123 :type tla: bool
1124
1125 :return: object for the newly created archive mirror.
1126 :rtype: `Archive`
1127
1128 :precondition: `self.is_registered()`
1129 :precondition: ``name`` is not a registered archive name
1130 :precondition: ``location`` does not exist and can be created
1131 :postcondition: Archive(name).is_registered()
1132
1133 :raise errors.NamespaceError: ``name`` is not a valid archive name.
1134 """
1135 deprecated_callable(Archive.make_mirror, ArchiveLocation.create_mirror)
1136 a = Archive(name)
1137 official_name = self.official_name
1138 self._impl.make_mirror(official_name, name, location,
1139 signed, listing, tla)
1140 return a
1141
1142 - def mirror(self, limit=None, fromto=None,
1143 no_cached=False, cached_tags=False):
1144 """Deprecated.
1145
1146 :see: `ArchiveLocation.make_mirrorer`
1147
1148 :param limit: restrict mirrorring to those archive items. All items
1149 must belong to this archive.
1150 :type limit: iterable of at least one ArchiveItem or str
1151
1152 :param fromto: update the mirror specified by the second item with the
1153 contents of the archive specified by the first item.
1154 :type fromto: sequence of exactly two Archive or str.
1155
1156 :precondition: If ``fromto`` is provided, both items must be registered
1157 archives names whose official name is this archive.
1158
1159 :param no_cached: do not copy cached revisions.
1160 :type no_cached: bool
1161
1162 :param cached_tags: copy only cachedrevs for tags to other archives.
1163 :type cached_tags: bool
1164 """
1165 deprecated_callable(Archive.mirror, ArchiveLocation.make_mirrorer)
1166 assert no_cached + cached_tags < 2
1167 assert limit is None or len(limit) > 0
1168 if fromto is None:
1169 from_, to = self.name, None
1170 else:
1171 from_, to = self._impl.mirror_fromto(fromto)
1172 args = ['archive-mirror']
1173 if no_cached:
1174 args.append('--no-cached')
1175 if cached_tags:
1176 args.append('--cached-tags')
1177 args.append(from_)
1178 if to is not None:
1179 args.append(to)
1180 if limit is not None:
1181 args.extend([self._archive_limit_param(L) for L in limit])
1182 backend.null_cmd(args)
1183
1202
1203
1205 if backend.version.release < (1, 3, 0):
1206 return _Archive_Baz_1_0
1207 else:
1208 return _Archive_Baz_1_3
1209
1210
1212
1215
1216 archive_meta_info_args = staticmethod(archive_meta_info_args)
1217
1231
1232 register_archive = staticmethod(register_archive)
1233
1234 - def make_mirror(master, name, location, signed, listing, tla):
1235 args = ['make-archive', '--mirror', master]
1236 if signed:
1237 args.append('--signed')
1238 if listing:
1239 args.append('--listing')
1240 if tla:
1241 args.append('--tla')
1242 args.extend((name, location))
1243 backend.null_cmd(args)
1244
1245 make_mirror = staticmethod(make_mirror)
1246
1248 return ('categories', '--archive', name)
1249
1250 iter_categories_args = staticmethod(iter_categories_args)
1251
1258
1259 _registered_archive_param = staticmethod(_registered_archive_param)
1260
1262 return [_Archive_Baz_1_0._registered_archive_param(A) for A in fromto]
1263
1264 mirror_fromto = staticmethod(mirror_fromto)
1265
1266
1268
1271
1272 archive_meta_info_args = staticmethod(archive_meta_info_args)
1273
1275 match = re.match('[^/]+://', location)
1276 return match is not None
1277
1278 _is_url = staticmethod(_is_url)
1279
1284
1285 _absolutize = classmethod(_absolutize)
1286
1288
1289
1290
1291
1292 args = ['whereis-archive', '--all-locations', official_name]
1293 import sets
1294 locations_with = sets.Set(backend.sequence_cmd(args))
1295 args = ['register-archive', '--delete', absolute_location]
1296 backend.null_cmd(args)
1297 if len(locations_with) == 1:
1298 difference = locations_with
1299 else:
1300 args = ['whereis-archive', '--all-locations', official_name]
1301 locations_without = sets.Set(backend.sequence_cmd(args))
1302 difference = locations_with - locations_without
1303 assert len(difference) == 1
1304 canonical_location = difference.pop().rstrip('\n')
1305 return canonical_location
1306
1307 _canonical_location_unregister = staticmethod(
1308 _canonical_location_unregister)
1309
1311 home = DirName(os.environ['HOME'])
1312 locations_dir = home/'.arch-params'/'=locations'
1313 if not os.path.isdir(locations_dir):
1314 os.mkdir(locations_dir)
1315 print >> open(locations_dir/name, 'w'), canonical_location
1316
1317 _register_name = staticmethod(_register_name)
1318
1322
1323 _location_meta_info = staticmethod(_location_meta_info)
1324
1337
1338 register_archive = classmethod(register_archive)
1339
1340 - def make_mirror(cls, master, name, location, signed, listing, tla):
1341 absolute_location = cls._absolutize(location)
1342 _Archive_Baz_1_0.make_mirror(master, name, absolute_location,
1343 signed, listing, tla)
1344 canonical_location = cls._canonical_location_unregister(
1345 master, absolute_location)
1346 cls._register_name(name, canonical_location)
1347
1348 make_mirror = classmethod(make_mirror)
1349
1351 return ('categories', name)
1352
1353 iter_categories_args = staticmethod(iter_categories_args)
1354
1356 return [Archive(_unsafe((A,))).location
1357 for A in _Archive_Baz_1_0.mirror_fromto(fromto)]
1358
1359 mirror_fromto = staticmethod(mirror_fromto)
1360
1361
1362 -class Category(Setupable, BranchIterable):
1363
1364 """Arch category namespace object.
1365
1366 :see: `Archive`, `Branch`, `Version`, `Revision`
1367 """
1368
1385
1387 """Instanciate a branch belonging to this category.
1388
1389 For example ``Category('jdoe@example.com/frob')['devel']`` is
1390 equivalent to ``Branch('jdoe@example.com/frob--devel')``.
1391
1392 :param b: branch id.
1393 :type b: str
1394 :rtype: `Category`
1395
1396 :raise NamespaceError: argument is not a valid branch id.
1397 """
1398 if b is not None and not NameParser.is_branch_name(b):
1399 raise errors.NamespaceError(b, 'unqualified branch name')
1400 if b is None:
1401 return Branch(_unsafe((self._archive, self._nonarch)))
1402 else:
1403 return Branch(_unsafe((self._archive,
1404 "%s--%s" % (self._nonarch, b))))
1405
1414
1418
1422
1433
1437
1438 branches = property(_get_branches, doc="""
1439 Deprecated.
1440
1441 Branches in this category.
1442
1443 :type: tuple of `Branch`
1444 :see: `Category.iter_branches`
1445 """)
1446
1458
1463
1464 library_branches = property(_get_library_branches, doc="""
1465 Deprecated.
1466
1467 Branches in this category present in the library.
1468
1469 :type: tuple of `Branch`
1470 :see: `Category.iter_branches`
1471 """)
1472
1473
1474 -class Branch(CategoryItem, Package, VersionIterable):
1475
1476 """Arch branch namespace object.
1477
1478 :see: `Archive`, `Category`, `Version`, `Revision`
1479 """
1480
1499
1501 """Instanciate a version belonging to this branch.
1502
1503 For example ``Branch('jdoe@example.com/frob--devel')['0']`` is
1504 equivalent to ``Branch('jdoe@example.com/frob--devel--0')``.
1505
1506 :param v: branch id.
1507 :type v: str
1508 :rtype: `Version`
1509
1510 :raise NamespaceError: argument is not a valid version id.
1511 """
1512 if not NameParser.is_version_id(v):
1513 raise errors.NamespaceError(v, 'version id')
1514 return Version(_unsafe((self._archive, "%s--%s" % (self._nonarch, v))))
1515
1524
1526 args = ['versions']
1527 if reverse:
1528 args.append('--reverse')
1529 args.append(self.fullname)
1530 for v in backend.sequence_cmd(args):
1531 yield Version(_unsafe((self._archive, v)))
1532
1536
1547
1551
1552 versions = property(_get_versions, doc="""
1553 Deprecated.
1554
1555 Versions in this branch.
1556
1557 :type: tuple of `Version`
1558 :see: `iter_versions`
1559 """)
1560
1572
1577
1578 library_versions = property(_get_library_versions, doc="""
1579 Deprecated.
1580
1581 Versions in this branch present in the library.
1582
1583 :type: tuple of `Version`
1584 :see: `iter_library_versions`
1585 """)
1586
1588 """Deprecated.
1589
1590 Latest version in this branch.
1591
1592 :rtype: `Version`
1593 :precondition: `self.exists()` returns ``True``
1594 :precondition: `self.iter_versions` yields at least one object.
1595 :raise IndexError: this branch is empty.
1596 :see: `latest_version`
1597 """
1598 deprecated_callable(self.as_version, self.latest_version)
1599 return list(self.iter_versions(reverse=True))[0]
1600
1602 """Latest version in this branch.
1603
1604 :rtype: `Version`
1605 :precondition: `self.exists()` returns ``True``
1606 :precondition: `self.iter_versions` yields at least one object.
1607 :raise ValueError: the archive is not registered, or this branch does
1608 not exist, or it contains no version.
1609 """
1610 try:
1611 return self.iter_versions(reverse=True).next()
1612 except errors.ExecProblem:
1613 try:
1614 self_exists = self.exists()
1615 except errors.ArchiveNotRegistered:
1616 raise ValueError('Archive is not registered: %s'
1617 % self.archive)
1618 if not self_exists:
1619 raise ValueError('Branch does not exist: %s' % self)
1620 raise
1621 except StopIteration:
1622 raise ValueError('Branch contains no version: %s' % self)
1623
1624
1625
1626 -class Version(BranchItem, Package, RevisionIterable):
1627
1628 """Arch version namespace object.
1629
1630 :see: `Archive`, `Category`, `Branch`, `Revision`
1631 """
1632
1651
1653 """Instanciate a revision belonging to this version.
1654
1655 Given a string, instanciate the revision of this version with the given
1656 patchlevel. For example
1657 ``Version('jdoe@example.com/frob--devel--0')['patch-1']`` is equivalent
1658 to ``Revision('jdoe@example.com/frob--devel--0--patch-1')``.
1659
1660 Given an integer, instanciate the *existing* revision of this version
1661 with the given index. For example, if ``version`` contains at least one
1662 revision, ``version[0]`` is equivalent to ``version['base-0']``, and
1663 ``version[-1]`` is equivalent to ``version.latest_revision()``.
1664
1665 :param idx: patch level, or revision number
1666 :type idx: str, int
1667 :rtype: `Revision`
1668
1669 :raise NamespaceError: argument is a string not a valid version
1670 patchlevel.
1671 :raise ValueError: argument is an integer and the version contains no
1672 revision with that index.
1673 """
1674 if isinstance(idx, str):
1675 return self._getitem_str(idx)
1676 if isinstance(idx, int):
1677 return self._getitem_int(idx)
1678 else:
1679 raise TypeError(
1680 'Version indices must be str or int, but was %r' % (idx,))
1681
1686
1688 if idx < 0:
1689 reverse = True
1690 decounter = - idx - 1
1691 else:
1692 reverse = False
1693 decounter = idx
1694 assert decounter >= 0
1695 rev_iter = self.iter_revisions(reverse)
1696 try:
1697 while decounter > 0:
1698 decounter -= 1
1699 rev_iter.next()
1700 return rev_iter.next()
1701 except StopIteration:
1702 raise IndexError(
1703 'Version index out of bounds: %r[%d]' % (self, idx))
1704
1706 """Deprecated.
1707
1708 This version.
1709
1710 :rtype: `Version`
1711 """
1712 deprecated_callable(self.as_version, because='Foolish consistency.')
1713 return self
1714
1723
1724 - def get(self, dir, link=False):
1725 """Construct a project tree for this version.
1726
1727 Extract the latest revision for this version from the archive. That is
1728 a shortcut for ``version.latest_revision.get(dir)``. It can be
1729 susceptible to race conditions when a concurrent transaction occurs on
1730 the same version, yielding a latter revision that what you may have
1731 meant.
1732
1733 :param dir: path of the project tree to create. Must not
1734 already exist.
1735 :type dir: str
1736 :param link: hardlink files to revision library instead of copying
1737 :type link: bool
1738 :return: newly created project tree.
1739 :rtype: `WorkingTree`
1740 """
1741 args = self._impl.get_args(self, dir, link)
1742 backend.null_cmd(args)
1743 return WorkingTree(dir)
1744
1746 args = ['revisions']
1747 if reverse:
1748 args.append('--reverse')
1749 args.append(self.fullname)
1750 for lvl in backend.sequence_cmd(args):
1751 yield Revision(_unsafe((self._archive, self._nonarch, lvl)))
1752
1754 """Revisions present in this version at specified archive location.
1755
1756 :warning: This is a temporary facility that does no sanity checking. It
1757 will be removed shortly after bound namespace objects are properly
1758 implemented.
1759 """
1760 version_url = location.url + '/' + self.nonarch
1761 for level in backend.sequence_cmd(['revisions', version_url]):
1762 yield Revision(_unsafe((self._archive, self._nonarch, level)))
1763
1767
1778
1782
1783 revisions = property(_get_revisions, doc="""
1784 Deprecated.
1785
1786 Revisions in this version.
1787
1788 :type: tuple of `Revision`
1789 :see: `iter_revisions`
1790 """)
1791
1803
1808
1809 library_revisions = property(_get_library_revisions, doc="""
1810 Deprecated.
1811
1812 Revisions in this version present in the library.
1813
1814 :type: tuple of `Revision`
1815 :see: `iter_library_revisions`
1816 """)
1817
1818 - def iter_merges(self, other=None, reverse=False, metoo=True):
1819 """Iterate over merge points in this version.
1820
1821 This method is mostly useful to save multiple invocations of
1822 the command-line tool and multiple connection to a remote
1823 archives when building an ancestry graph. Ideally, it would
1824 not be present and the desired merge graph traversal would be
1825 done using the new_patches and merges properties of Patchlog
1826 objects.
1827
1828 :param other: list merges with that version.
1829 :type other: `Version`
1830 :param reverse: reverse order, recent revisions first.
1831 :type reverse: bool
1832 :param metoo: do not report the presence of a patch within itself
1833 :type metoo: bool
1834
1835 :return: Iterator of tuples (R, T) where R are revisions in this
1836 version and T are iterable of revisions in the ``other`` version.
1837 :rtype: iterable of `Revision`
1838 """
1839 if other is None: othername = None
1840 else: othername = other.fullname
1841 flow = _arch.iter_merges(self.fullname, othername, reverse, metoo)
1842 last_target = None
1843 sources = []
1844 for target, source in flow:
1845 if last_target is None:
1846 last_target = target
1847 if target == last_target:
1848 sources.append(source)
1849 else:
1850 yield self[last_target], itertools.imap(Revision, sources)
1851 last_target = target
1852 sources = [source]
1853 yield self[last_target], itertools.imap(Revision, sources)
1854
1856 """Iterate over the cached revisions in this version.
1857
1858 :rtype: iterator of `Revision`
1859 """
1860 for rev in _arch.cachedrevs(self.fullname):
1861 lvl = rev.split('--')[-1]
1862 yield self[lvl]
1863
1864
1866
1867 """Arch revision namespace object.
1868
1869 :see: `Archive`, `Category`, `Branch`, `Version`
1870 :group Libray Methods: library_add, library_remove, library_find
1871 :group History Methods: get_ancestor, get_previous, iter_ancestors
1872 """
1873
1894
1896 """Deprecated
1897
1898 Returns this revision. For consistency with `Package.as_revision()`.
1899
1900 :rtype: `Revision`
1901 """
1902 deprecated_callable(self.as_revision, because='Foolish consistency.')
1903 return self
1904
1917
1918 - def get(self, dir, link=False):
1919 """Construct a project tree for this revision.
1920
1921 Extract this revision from the archive.
1922
1923 :param dir: path of the project tree to create. Must not
1924 already exist.
1925 :type dir: str
1926 :param link: hardlink files to revision library instead of copying
1927 :type link: bool
1928 :return: newly created project tree.
1929 :rtype: `WorkingTree`
1930 """
1931 args = self._impl.get_args(self, dir, link)
1932 backend.null_cmd(args)
1933 return WorkingTree(dir)
1934
1936 """Fetch the changeset associated to this revision.
1937
1938 :param dir: name of the changeset directory to create. Must
1939 not already exist.
1940 :type dir: str
1941 :return: changeset associated to this revision.
1942 :rtype: `Changeset`
1943 """
1944 _arch.get_patch(self.fullname, dir)
1945 return Changeset(dir)
1946
1957
1959 return self.__patchlog
1960
1961 patchlog = property(_get_patchlog, doc="""
1962 Patchlog associated to this revision.
1963
1964 The `Patchlog` object is created in `__init__`, since log parsing is
1965 deferred that has little overhead and avoid parsing the log for a given
1966 revision several times. The patchlog data is read from the archive.
1967
1968 :type: `Patchlog`
1969 :see: `ArchSourceTree.iter_logs`
1970 """)
1971
1973 """Create a continuation of this revision in the target version.
1974
1975 :param target: version to create a continuation into. If it does not
1976 exist yet, it is created.
1977 :type target: Version
1978 """
1979 _check_version_param(target, 'target')
1980 target_name = target.fullname
1981 _arch.tag(self.fullname, target_name)
1982
1984 """Add this revision to the library.
1985
1986 :postcondition: self in self.version.iter_library_revisions()
1987 """
1988 _arch.library_add(self.fullname)
1989
1991 """Remove this revision from the library.
1992
1993 :precondition: self in self.version.iter_library_revisions()
1994 :postcondition: self not in self.version.iter_library_revisions()
1995 """
1996 _arch.library_remove(self.fullname)
1997
1999 """The copy of this revision in the library.
2000
2001 :rtype: `LibraryTree`
2002 :precondition: self in self.version.iter_library_revisions()
2003 """
2004 return LibraryTree(_arch.library_find(self.fullname))
2005
2006
2007
2008
2010 """Deprecated.
2011
2012 Parent revision.
2013
2014 :return:
2015 - The previous namespace revision, if this revision is regular
2016 commit.
2017 - The tag origin, if this revision is a continuation
2018 - ``None`` if this revision is an import.
2019
2020 :rtype: `Revision` or None
2021 :see: `Revision.ancestor`
2022 """
2023 deprecated_callable(self.get_ancestor, (Revision, 'ancestor'))
2024 return self.ancestor
2025
2027 args = ['ancestry-graph', '--immediate', self.fullname]
2028
2029 revision_id = backend.one_cmd(args)
2030 if revision_id == '(null)':
2031 return None
2032 return Revision(revision_id)
2033
2034 ancestor = property(_get_ancestor, doc="""
2035 Parent revision.
2036
2037 - The previous namespace revision, if this revision is regular commit.
2038 - The tag origin, if this revision is a continuation
2039 - ``None`` if this revision is an import.
2040
2041 :type: `Revision` or None
2042 """)
2043
2045 """Deprecated.
2046
2047 Previous namespace revision.
2048
2049 :return: the previous revision in the same version, or None if this
2050 revision is a ``base-0``.
2051 :rtype: `Revision` or None
2052 :see: `Revision.previous`
2053 """
2054 deprecated_callable(self.get_previous, (Revision, 'previous'))
2055 return self.previous
2056
2065
2066 previous = property(_get_previous, doc="""
2067 Previous namespace revision.
2068
2069 The previous revision in the same version, or None if this revision is a
2070 ``base-0``.
2071
2072 :type: `Revision` or None
2073 """)
2074
2076 """Ancestor revisions.
2077
2078 :param metoo: yield ``self`` as the first revision.
2079 :type metoo: bool
2080 :return: all the revisions in that line of development.
2081 :rtype: iterable of `Revision`
2082 """
2083 args = ['ancestry-graph']
2084 args.append(self.fullname)
2085 lines = iter(backend.sequence_cmd(args))
2086 if not metoo:
2087 lines.next()
2088 for line in lines:
2089 ancestor, merge = line.split('\t')
2090 yield Revision(ancestor)
2091
2092 - def cache(self, cache=None):
2093 """Cache a full source tree for this revision in its archive.
2094
2095 :param cache: cache root for trees with pristines.
2096 :type cache: bool
2097 """
2098 _arch.cacherev(self.fullname, cache)
2099
2101 """Remove the cached tree of this revision from its archive."""
2102 _arch.uncacherev(self.fullname)
2103
2108
2112
2114 if self.archive._is_tla_format():
2115 return self._tla_file_url(name)
2116 if self.archive._is_baz_format():
2117 return self._baz_file_url(name)
2118 raise AssertionError, \
2119 'did not recognize archive version of %s' % self.archive
2120
2121 _checksum_regex = re.compile(
2122 "^Signature-for: (.*)/(.*)\n"
2123 "([a-zA-Z0-9]+ [^/\\s]+ [a-fA-F0-9]+\n)*",
2124 re.MULTILINE)
2125
2127 match = self._checksum_regex.search(text)
2128 checksum_body = match.group()
2129 checksum_lines = checksum_body.strip().split('\n')
2130 checksum_words = map(lambda x: x.split(), checksum_lines)
2131 assert checksum_words[0] == ['Signature-for:', self.fullname]
2132 del checksum_words[0]
2133 checksums = {}
2134 for algo, name, value in checksum_words:
2135 name_sums = checksums.setdefault(name, dict())
2136 name_sums[algo] = value
2137 return checksums
2138
2140 """Files stored in the archive for that revision.
2141
2142 :rtype: iterable of `RevisionFile`
2143 """
2144 import urllib
2145 for checksum_name, can_fail in \
2146 (('checksum', False), ('checksum.cacherev', True)):
2147 try:
2148 checksum_file = urllib.urlopen(self._file_url(checksum_name))
2149 except IOError:
2150 if can_fail: continue
2151 else: raise
2152 try:
2153 checksum_data = checksum_file.read()
2154 finally:
2155 checksum_file.close()
2156 yield RevisionFile(self, checksum_name, {})
2157 checksums = self._parse_checksum(checksum_data)
2158 for name, name_sums in checksums.items():
2159 yield RevisionFile(self, name, name_sums)
2160
2161 - def apply(self, tree, reverse=False):
2162 """Replay this revision on this tree. Raise on conflict.
2163
2164 :param tree: the tree to apply changes to.
2165 :type tree: `WorkingTree`
2166 :param reverse: invert the meaning of the changeset; adds
2167 become deletes, etc.
2168 :type reverse: bool
2169 :raise errors.ChangesetConflict: a conflict occured while replaying the
2170 revision.
2171 """
2172 _check_working_tree_param(tree, 'tree')
2173 args = self._impl.replay_args(self, tree, reverse)
2174 status = backend.status_cmd(args, expected=(0,1))
2175 if status == 1:
2176 raise errors.ChangesetConflict(tree, self)
2177
2178
2180
2182 args = ['replay', '--dir', str(tree)]
2183 if reverse:
2184 args.append('--reverse')
2185 args.append(rev.fullname)
2186 return args
2187
2188 replay_args = staticmethod(replay_args)
2189
2190 - def get_args(revision, dir, link=False):
2191 args = ['get']
2192 if link:
2193 args.append('--link')
2194 args.extend((revision.fullname, str(dir)))
2195 return args
2196
2197 get_args = staticmethod(get_args)
2198
2199
2201 if backend.version.release < (1, 4, 0):
2202 return _Revision_Baz_1_0
2203 else:
2204 return _Revision_Baz_1_4
2205
2206
2208
2211
2212 revision_from_previous = staticmethod(revision_from_previous)
2213
2214
2216
2219
2220 revision_from_previous = staticmethod(revision_from_previous)
2221
2222
2223 public('RevisionFile')
2224
2226
2227 """File component of an archived revision.
2228
2229 :ivar revision: revision this file belongs to.
2230 :type revision: `Revision`
2231 :ivar name: name of that file.
2232 :type name: str
2233 :ivar checksums: dictionnary whose keys are checksum algorithms
2234 (e.g. ``"md5"``, ``"sha1"``) and whose values are checksum
2235 values (strings of hexadecimal digits).
2236 :type checksums: dict of str to str
2237 """
2238
2239 - def __init__(self, revision, name, checksums):
2243
2245 import urllib
2246 my_file = urllib.urlopen(self.revision._file_url(self.name))
2247 try:
2248 ret = my_file.read()
2249 finally:
2250 my_file.close()
2251 return ret
2252
2253 data = property(_get_data,
2254 """Content of of that file.
2255
2256 :type: str
2257 """)
2258
2259
2260
2261
2262 public('Patchlog')
2263
2264 from _patchlog import Patchlog
2265
2266 public('LogMessage')
2267
2268 from _logmessage import LogMessage
2269
2270
2271
2272
2273 public(
2274 'init_tree',
2275 'in_source_tree',
2276 'tree_root',
2277 )
2278
2279 -def init_tree(directory, version=None, nested=False):
2280 """Initialize a new project tree.
2281
2282 :param directory: directory to initialize as a source tree.
2283 :type directory: str
2284 :param version: if given, set the the ``tree-version`` and create an empty
2285 log version.
2286 :type version: `Version`
2287 :param nested: if true, the command will succeed even if 'directory'
2288 is already within a source tree.
2289 :type nested: bool
2290 :return: source tree object for the given directory.
2291 :rtype: `WorkingTree`
2292 """
2293 if version is not None:
2294 version = _version_param(version)
2295 _arch.init_tree(directory, version, nested)
2296 return WorkingTree(directory)
2297
2298
2300 """Is directory inside a Arch source tree?
2301
2302 :param directory: test if that directory is in an Arch source tree.
2303 :type directory: str
2304 :return: whether this directory is inside an Arch source tree.
2305 :rtype: bool
2306
2307 :warning: omitting the ``directory`` argument is deprecated.
2308 """
2309 if directory is None:
2310 deprecated_usage(
2311 in_source_tree, "Argument defaults to current direcotry.")
2312 directory = '.'
2313 return _arch.in_tree(directory)
2314
2315
2317 """SourceTree containing the given directory.
2318
2319 :param directory: give the ``tree-root`` of this directory. Specify "." to
2320 get the ``tree-root`` of the current directory.
2321 :type directory: str
2322 :return: source tree containing ``directory``.
2323 :rtype: `ArchSourceTree`
2324
2325 :warning: omitting the ``directory`` argument is deprecated.
2326 """
2327 if directory is None:
2328 deprecated_usage(tree_root, "Argument defaults to current directory.")
2329 directory = '.'
2330 root = _arch.tree_root(directory)
2331
2332 return SourceTree(root)
2333
2334
2335 public('SourceTree',
2336 'ForeignTree',
2337 'ArchSourceTree',
2338 'LibraryTree',
2339 'WorkingTree')
2340
2342
2343 """Abstract base class for `ForeignTree` and `ArchSourceTree`."""
2344
2346 """Create a source tree object for the given root path.
2347
2348 `ForeignTree` if root does not point to a Arch source tree.
2349 `LibraryTree` if root is a tree in the revision library. `WorkingTree`
2350 if root is a Arch source tree outside of the revision library.
2351
2352 If root is omitted, use the tree-root of the current working directory.
2353 """
2354 __pychecker__ = 'no-returnvalues'
2355
2356 if cls is not SourceTree:
2357 assert root is not None
2358 return DirName.__new__(cls, root)
2359 else:
2360 if not root:
2361 root = _arch.tree_root(os.getcwd())
2362 root = DirName(root).realpath()
2363 if _is_tree_root(root):
2364 for revlib in _arch.iter_revision_libraries():
2365 if root.startswith(revlib):
2366 return LibraryTree(root)
2367 return WorkingTree(root)
2368 else:
2369 assert not _arch.in_tree(root)
2370 return ForeignTree(root)
2371
2372
2374 """Generic source tree without Arch support.
2375
2376 Unlike Arch source trees, the root may not even exist.
2377 """
2379
2380
2382 """Return True if dir is a Arch source tree."""
2383 return os.path.isdir(os.path.join(dir, '{arch}'))
2384
2385
2387
2388 """Abstract base class for Arch source trees."""
2389
2403 tree_version = property(get_tree_version)
2404
2406 path = os.path.join(self, '{arch}', '++default-version')
2407 try:
2408 return open(path, 'r').read().rstrip('\n')
2409 except IOError:
2410 if not os.path.exists(vsn_name):
2411 return None
2412 raise
2413
2415 """Revision of the last patchlog for the tree-version.
2416
2417 :raise errors.TreeVersionError: no valid default version set.
2418 :raise IOError: unable to read the ++default-version file.
2419 """
2420 reverse_logs = self.iter_logs(reverse=True)
2421 try: last_log = reverse_logs.next()
2422 except StopIteration:
2423 raise RuntimeError('no logs for the tree-version')
2424 return last_log.revision
2425 tree_revision = property(_get_tree_revision)
2426
2428 if not _is_tree_root(self):
2429 raise errors.SourceTreeError(str(self))
2430 assert os.path.isdir(self)
2431
2434 tagging_method = property(get_tagging_method)
2435
2436
2437 - def iter_inventory(self, source=False, precious=False, backups=False,
2438 junk=False, unrecognized=False, trees=False,
2439 directories=False, files=False, both=False,
2440 names=False, limit=None):
2441 """Tree inventory.
2442
2443 The kind of files looked for is specified by setting to
2444 ``True`` exactly one of the following keyword arguments:
2445
2446 ``source``, ``precious``, ``backups``, ``junk``,
2447 ``unrecognized``, ``trees``.
2448
2449 If the ``trees`` argument is not set, whether files, directory
2450 or both should be listed is specified by setting to ``True``
2451 exactly one of the following keyword arguments:
2452
2453 ``directories``, ``files``, ``both``.
2454
2455 :keyword source: list source files only.
2456 :keyword precious: list precious files only.
2457 :keyword backups: list backup files only.
2458 :keyword junk: list junk files only.
2459 :keyword unrecognized: list unrecognized files only.
2460 :keyword trees: list nested trees only. If this is true, the
2461 iterator wil only yield `ArchSourceTree` objects.
2462
2463 :keyword directories: list directories only,
2464 yield only `FileName` objects.
2465 :keyword files: list files only, yield only `DirName` objects.
2466 :keyword both: list both files and directories,
2467 yield both FileName and `DirName` objects.
2468
2469 :keyword name: do inventory as if the id-tagging-method was
2470 set to ``names``. That is useful to ignore
2471 ``untagged-source`` classification.
2472
2473 :keyword limit: restrict the inventory to this directory. Must
2474 be the name of a directory relative to the tree root.
2475
2476 :rtype: iterable of `FileName`, `DirName`, `ArchSourceTree`
2477 according to the arguments.
2478 """
2479 __pychecker__ = 'maxargs=12'
2480 name_filter = self.__inventory_filter(trees, directories, files, both)
2481 name_iterator = self.__inventory_helper(
2482 ['inventory'], source, precious, backups, junk, unrecognized,
2483 trees, directories, files, both, names, limit)
2484
2485 return itertools.imap(name_filter, name_iterator)
2486
2487 - def iter_inventory_ids(self,source=False, precious=False, backups=False,
2488 junk=False, unrecognized=False, trees=False,
2489 directories=False, files=False, both=False,
2490 limit=None):
2491 """Tree inventory with file ids.
2492
2493 :see: `ArchSourceTree.iter_inventory`
2494
2495 :rtype: iterable of tuples ``(id, item)``, where ``item`` is
2496 `FileName`, `DirName`, `ArchSourceTree` according to the
2497 arguments and ``id`` is the associated inventory id.
2498 """
2499 __pychecker__ = 'maxargs=11'
2500 name_filter = self.__inventory_filter(trees, directories, files, both)
2501 def id_name_filter(line):
2502 name, id_ = line.split('\t')
2503 return id_, name_filter(name)
2504 id_name_iterator = self.__inventory_helper(
2505 ['inventory', '--ids'], source, precious, backups, junk,
2506 unrecognized, trees, directories, files, both,
2507 names=False, limit=limit)
2508
2509 return itertools.imap(id_name_filter, id_name_iterator)
2510
2512 types = trees, directories, files, both
2513 assert 1 == sum([bool(t) for t in types])
2514 trees, directories, files, both = types
2515 if trees:
2516 return self.__inventory_filter_trees
2517 if directories:
2518 return self.__inventory_filter_directories
2519 if files:
2520 return self.__inventory_filter_files
2521 if both:
2522 return self.__inventory_filter_both
2523 raise AssertionError('unreachable')
2524
2527
2530
2533
2535 __pychecker__ = 'no-returnvalues'
2536 f = name_unescape(f)
2537 if os.path.isfile(self/f):
2538 return FileName(f)
2539 elif os.path.islink(self/f):
2540 return FileName(f)
2541 elif os.path.isdir(self/f):
2542 return DirName(f)
2543 else:
2544 raise AssertionError("neither file, link, nor dir: %r" % (self/f,))
2545
2546 - def __inventory_helper(self, opts,
2547 source, precious, backups, junk, unrecognized,trees,
2548 directories, files, both, names, limit):
2549 __pychecker__ = 'maxargs=13'
2550
2551 classes = source, precious, backups, junk, unrecognized, trees
2552 classes = [bool(X) for X in classes]
2553 assert 1 == sum(classes)
2554 class_opts = ['--source', '--precious', '--backups', '--junk',
2555 '--unrecognized', '--trees']
2556 types = directories, files, both
2557 types = [bool(X) for X in types]
2558 assert 1 == sum(types) + bool(trees)
2559 type_opts = ['--directories', '--files', '--both']
2560 for flag, opt in zip(classes + types, class_opts + type_opts):
2561 if flag:
2562 opts.append(opt)
2563 if names:
2564 opts.append('--names')
2565 if limit is not None:
2566 self._check_relname_param(limit, 'limit')
2567 opts.append(str(limit))
2568 return backend.sequence_cmd(opts, chdir=str(self))
2569
2570
2572 """Internal argument checking utility"""
2573 if not isinstance(param, basestring):
2574 exc_type = TypeError
2575 elif os.path.isabs(param):
2576 exc_type = ValueError
2577 else:
2578 return
2579 raise exc_type("Parameter \"%s\" must be a relative path (string)"
2580 " but was: %r" % (name, param))
2581
2583 """Deprecated.
2584
2585 Inventory of the source tree as a list.
2586
2587 :see: `iter_inventory`
2588 """
2589
2590 return list (self.iter_inventory(*args, **kw))
2591
2593 return util.sorttree(self.inventory(source=True, both=True))
2594
2596 """Iterate over versions this tree has a log-version for.
2597
2598 :param limit: only iterate log-versions in this namespace.
2599 :type limit: `Archive`, `Category`, `Branch`, `Version`
2600 :param reverse: yield log-versions in reverse order.
2601 :type reverse: bool
2602 """
2603 kwargs = {}
2604 if isinstance(limit, Archive):
2605 kwargs['archive'] = limit.name
2606 elif isinstance(limit, (Category, Branch, Version)):
2607 kwargs['archive'] = limit.archive.name
2608 if isinstance(limit, Category): kwargs['category'] = limit.nonarch
2609 elif isinstance(limit, Branch): kwargs['branch'] = limit.nonarch
2610 elif isinstance(limit, Version): kwargs['version'] = limit.nonarch
2611 elif limit is not None and not isinstance(limit, Archive):
2612 raise TypeError("Expected Archive, Category, Branch or Version"
2613 " but got: %r" % limit)
2614 for vsn in _arch.iter_log_versions(self, reverse=reverse, **kwargs):
2615 yield Version(vsn)
2616
2617 - def iter_logs(self, version=None, reverse=False):
2618 """Iterate over patchlogs present in this tree.
2619
2620 :param version: list patchlogs from this version. Defaults to
2621 the tree-version.
2622 :type version: `Version`
2623 :param reverse: iterate more recent logs first.
2624 :type reverse: bool
2625 :return: patchlogs from ``version``.
2626 :rtype: iterator of `Patchlog`.
2627 :raise errors.TreeVersionError: no valid default version set.
2628 :raise IOError: unable to read the ++default-version file.
2629 """
2630 if version is None:
2631 version = self.tree_version.fullname
2632 else:
2633 version = _version_param(version)
2634 for rvsn in _arch.iter_log_ls(self, version, reverse=reverse):
2635 yield Patchlog(_unsafe((rvsn,)), tree=self)
2636
2638 """Read a file id set by an explicit id tag or tagline.
2639
2640 FIXME: update docstring when support for pybaz<1.3 is dropped, as this
2641 release fixed "baz id" to report name-based ids correctly.
2642
2643 :param name: name of a source file relative to the tree-root.
2644 :type name: str
2645 :return: file id if the file has an explicit id or a tagline.
2646 :rtype: str
2647 """
2648 absname = str(self/name)
2649 if not os.path.exists(absname) and not os.path.islink(absname):
2650 raise IOError(2, 'No such file or directory', absname)
2651 args = ('id', absname)
2652 status, output = backend.status_one_cmd(args, expected=(0,1))
2653 if status == 1:
2654 return None
2655 return output.split('\t')[1]
2656
2658 """Find a pristine copy of a file for a given revision.
2659
2660 Will create the requested revision in the library or in the
2661 current tree pristines if needed.
2662
2663 :param name: name of the file.
2664 :type name: str
2665 :param revision: revision to look for the file into.
2666 :type revision: `Revision`
2667 :return: absolute path name of a pristine copy of the file.
2668 :rtype: `pathname.PathName`
2669 :raise errors.MissingFileError: file is not source or is not
2670 present in the specified revision.
2671 """
2672 revision = _revision_param(revision)
2673 result = _arch.file_find(self, name, revision)
2674 if result is None:
2675 raise errors.MissingFileError(self, name, revision)
2676
2677 result = os.path.join(self, result)
2678 return PathName(result)
2679
2680
2682
2683 """Read-only Arch source tree."""
2684
2686 """Create a LibraryTree object with the given root path.
2687
2688 Root must be a directory containing a Arch source tree in the
2689 revision library.
2690 """
2691 ArchSourceTree.__init__(self, root)
2692 self.check_is_tree_root()
2693
2694
2696
2697 """Working source tree, Arch source tree which can be modified."""
2698
2700 """Create WorkingTree object with the given root path.
2701
2702 Root must be a directory containing a valid Arch source tree
2703 outside of the revision library.
2704 """
2705 ArchSourceTree.__init__(self, root)
2706 self.check_is_tree_root()
2707 self._impl = _workingtree_impl()
2708
2710 """Adds the patchlogs in the given revision to the current tree.
2711
2712 Create a temporary source tree for ``revision``, then add all the
2713 patchlogs present in that tree to the current tree. No content
2714 is touched besides the patchlogs.
2715
2716 :param revision: revision to synchronize with.
2717 :type revision: `Version`, `Revision` or str
2718 :raise errors.NamespaceError: ``revision`` is not a valid
2719 version or revision name.
2720 """
2721 revision = _version_revision_param(revision)
2722 _arch.sync_tree(self, revision)
2723
2725 version = _version_param(version)
2726 version_path = os.path.join(str(self), '{arch}', '++default-version')
2727 print >> open(version_path, 'w'), version
2728
2731
2732 tree_version = property(ArchSourceTree.get_tree_version, set_tree_version)
2733
2735 """Are there uncommited changes is this source tree?
2736
2737 :rtype: bool
2738 """
2739 return self._impl.has_changes(str(self))
2740
2741 - def changes(self, revision=None, output=None):
2742 """Uncommited changes in this tree.
2743
2744 :param revision: produce the changeset between this revision
2745 and the tree. If ``revision`` is ``None``, use the
2746 tree-revision.
2747 :type revision: `Revision`, None
2748 :param output: absolute path of the changeset to produce.
2749 :type output: string
2750 :return: changeset between ``revision`` and the tree.
2751 :rtype: Changeset
2752 :raise errors.TreeVersionError: no valid default version set.
2753 :raise IOError: unable to read the ++default-version file.
2754 """
2755 if revision is None: revision = self.tree_revision
2756 _check_str_param(output, 'output')
2757 _check_revision_param(revision, 'revision')
2758 return delta(revision, self, output)
2759
2760 - def star_merge(self, from_=None, reference=None,
2761 forward=False, diff3=False):
2762 """Merge mutually merged branches.
2763
2764 :bug: if the merge causes a conflict, a RuntimeError is
2765 raised. You should not rely on this behaviour as it is
2766 likely to change in the future. If you want to support
2767 conflicting merges, use `iter_star_merge` instead.
2768
2769 :param `from_`: branch to merge changes from, ``None`` means the
2770 ``tree-version``.
2771 :type `from_`: None, `Version`, `Revision`, or str
2772 :param reference: reference version for the merge, ``None``
2773 means the ``tree-version``.
2774 :type reference: None, `Version` or str
2775 :param forward: ignore already applied patch hunks.
2776 :type forward: bool
2777 :param diff3: produce inline conflict markers instead of
2778 ``.rej`` files.
2779 :type diff3: bool
2780 :raise errors.NamespaceError: ``from_`` or ``reference`` is
2781 not a valid version or revision name.
2782 """
2783 if from_ is not None:
2784 from_ = _version_revision_param(from_)
2785 if reference is not None:
2786 reference = _version_revision_param(reference)
2787 if forward:
2788 deprecated_usage(WorkingTree.star_merge, (
2789 "forward=True has always been a no-op."))
2790 args = self._impl.star_merge_args(diff3)
2791 args.extend(('--dir', str(self)))
2792 if reference is not None:
2793 args.extend(('--reference', reference))
2794 if from_ is not None:
2795 args.append(from_)
2796
2797 backend.null_cmd(args)
2798
2799 - def iter_star_merge(self, from_=None, reference=None,
2800 forward=False, diff3=False):
2801 """Merge mutually merged branches.
2802
2803 :param `from_`: branch to merge changes from, ``None`` means the
2804 ``tree-version``.
2805 :type `from_`: None, `Version`, `Revision`, or str
2806 :param reference: reference version for the merge, ``None``
2807 means the ``tree-version``.
2808 :type reference: None, `Version` or str
2809 :param forward: ignore already applied patch hunks.
2810 :type forward: bool
2811 :param diff3: produce inline conflict markers instead of
2812 ``.rej`` files.
2813 :type diff3: bool
2814 :raise errors.NamespaceError: ``from_`` or ``reference`` is
2815 not a valid version or revision name.
2816 :rtype: `ChangesetApplication`
2817 """
2818
2819
2820 if from_ is not None:
2821 from_ = _version_revision_param(from_)
2822 if reference is not None:
2823 reference = _version_revision_param(reference)
2824 if forward:
2825 deprecated_usage(WorkingTree.iter_star_merge, (
2826 "forward=True has always been a no-op."))
2827 args = self._impl.star_merge_args(diff3)
2828 args.extend(('--dir', str(self)))
2829 if reference is not None:
2830 args.extend(('--reference', reference))
2831 if from_ is not None:
2832 args.append(from_)
2833 merge = backend.sequence_cmd(args, expected=(0,1))
2834 return ChangesetApplication(merge)
2835
2836 - def undo(self, revision=None, output=None, quiet=False, throw_away=False):
2837 """Undo and save changes in a project tree.
2838
2839 Remove local changes since revision and optionally save them
2840 as a changeset.
2841
2842 :keyword revision: revision to revert to. Default to the last
2843 revision of the tree-version for which a patchlog is present.
2844 :type revision: `Revision`, str
2845 :keyword output: name of the output changeset directory. Must
2846 not already exist. Default to an automatic ,,undo-N name
2847 in the working tree.
2848 :type output: str
2849 :keyword quiet: OBSOLETE. Incremental output is always discarded.
2850 :type quiet: bool
2851 :keyword throw_away: discard the output changeset and return
2852 ``None``. Must not be used at the same time as ``output``.
2853 :type throw_away: bool
2854 :return: changeset restoring the undone changes,
2855 or None if ``throw_away``.
2856 :rtype: `Changeset`, None
2857 """
2858 assert sum(map(bool, (output, throw_away))) < 2
2859 if output is None:
2860 output = util.new_numbered_name(self, ',,undo-')
2861 if revision is not None:
2862 revision = _revision_param(revision)
2863 _arch.undo(self, revision, output, quiet, throw_away)
2864 if throw_away: return None
2865 return Changeset(output)
2866
2867 - def redo(self, patch=None, keep=False, quiet=False):
2868 """Redo changes in a project tree.
2869
2870 Apply patch to the project tree and delete patch.
2871
2872 If patch is provided, it must be a Changeset object. Else, the highest
2873 numbered ,,undo-N directory in the project tree root is used.
2874
2875 If keep is true, the patch directory is not deleted.
2876 """
2877 _arch.redo(self, patch, keep, quiet)
2878
2881 tagging_method = property(ArchSourceTree.get_tagging_method,
2882 set_tagging_method)
2883
2885 _arch.add(self/file)
2886
2888 _arch.move(self/src, self/dest)
2889
2891
2892 dest = PathName(dest)
2893 assert os.path.exists((self/dest).dirname())
2894 os.rename(self/src, self/dest)
2895
2897 fullfile = self/file
2898 if os.path.isfile(fullfile):
2899 if _arch.has_explicit_id(fullfile):
2900 _arch.delete(fullfile)
2901 os.unlink(fullfile)
2902 elif os.path.isdir(fullfile):
2903 shutil.rmtree(fullfile)
2904
2906 fullfile = self/file
2907 if os.path.isfile(fullfile):
2908 os.unlink(fullfile)
2909 else:
2910 shutil.rmtree(fullfile)
2911
2913 if not os.path.islink(self/file):
2914 assert os.path.exists(self/file)
2915 _arch.delete(self/file)
2916
2918 """Archive a full-source base-0 revision.
2919
2920 If log is specified, it must be a LogMessage object or a file
2921 name as a string. If omitted, the default log message file of
2922 the tree is used.
2923
2924 The --summary, --log-message and --setup options to tla are
2925 mere CLI convenience features and are not directly supported.
2926 """
2927 if isinstance(log, LogMessage):
2928 log.save()
2929 log = log.name
2930 assert log is None or isinstance(log, str)
2931 if log is not None:
2932 log = os.path.abspath(log)
2933 self._impl.import_(str(self), log)
2934
2935 - def commit(self, log=None, strict=False, seal=False, fix=False,
2936 out_of_date_ok=False, file_list=None, version=None,
2937 just_commit=False):
2938 """Archive a changeset-based revision.
2939
2940 :keyword version: version in which to commit the revision.
2941 Defaults to the `tree_version`.
2942 :type version: `Version`, str
2943 :keyword log: Log message for this revision. Defaults to the log
2944 message file of the tree-version (the file created by
2945 ``tla make-log``.
2946 :type log: `LogMessage`
2947 :param strict: perform a strict tree-lint before commiting.
2948 :type strict: bool
2949 :param seal: create a ``version-0`` revision.
2950 :type seal: bool
2951 :param fix: create a ``versionfix`` revision.
2952 :type fix: bool
2953 :param out_of_date_ok: commit even if the tree is out of
2954 date.
2955 :type out_of_date_ok: bool
2956 :param file_list: Only commit changes to those files,
2957 specified relative to the tree-root.
2958 :type file_list: iterable of str, with at least one item.
2959 :param just_commit: only create new revision, do not add ancillary data
2960 like cachedrevs or ancestry files.
2961 :type just_commit: bool
2962
2963 The --summary and --log-message options to tla are mere CLI
2964 convenience features and are not directly supported.
2965
2966 :see: `WorkingTree.iter_commit`
2967 """
2968 for unused in self.iter_commit(
2969 log, strict, seal, fix, out_of_date_ok, file_list, version,
2970 just_commit):
2971 pass
2972
2974 """Standard arch log of newly merged patches.
2975
2976 :rtype: str
2977 """
2978 return _arch.log_for_merge(self)
2979
2980
2981 - def iter_commit(self, log=None, strict=False, seal=False, fix=False,
2982 out_of_date_ok=False, file_list=None, version=None,
2983 just_commit=False, stderr_too=False):
2984 """Archive a changeset-based revision, returning an iterator.
2985
2986
2987 :keyword version: version in which to commit the revision.
2988 Defaults to the `tree_version`.
2989 :type version: `Version`, str
2990 :keyword log: Log message for this revision. Defaults to the log
2991 message file of the tree-version (the file created by
2992 ``tla make-log``.
2993 :type log: `LogMessage`
2994 :keyword strict: perform a strict tree-lint before commiting.
2995 :type strict: bool
2996 :keyword seal: create a ``version-0`` revision.
2997 :type seal: bool
2998 :keyword fix: create a ``versionfix`` revision.
2999 :type fix: bool
3000 :keyword out_of_date_ok: commit even if the tree is out of
3001 date.
3002 :type out_of_date_ok: bool
3003 :keyword file_list: Only commit changes to those files,
3004 specified relative to the tree-root.
3005 :type file_list: iterable of str, with at least one item.
3006 :param just_commit: only create new revision, do not add ancillary data
3007 like cachedrevs or ancestry files.
3008 :type just_commit: bool
3009 :param stderr_too: iterate over stderr output as well as stdout.
3010 :type stderr_too: bool
3011 :rtype: iterator of `TreeChange`, `Chatter` or str
3012
3013 :warning: ``stderr_too=True`` is only supported with the
3014 PyArchSpawningStrategy. Using it will cause a ArgumentError with the
3015 TwistedSpawningStrategy. That will be fixed when the process handling
3016 subsystem is replaced by Gnarly.
3017
3018 The --summary and --log-message options to tla are mere CLI
3019 convenience features and are not directly supported.
3020
3021 :see: `WorkingTree.commit`
3022 """
3023
3024
3025
3026 args = ['commit']
3027 if just_commit:
3028 args.extend(self._impl.commit_just_commit)
3029 if log is not None:
3030 if isinstance(log, LogMessage):
3031 log.save()
3032 log = log.name
3033 assert isinstance(log, str)
3034 log = os.path.abspath(log)
3035 args.extend(('--log', log))
3036 if strict:
3037 args.append('--strict')
3038 assert not (seal and fix)
3039 if seal:
3040 args.append('--seal')
3041 if fix:
3042 args.append('--fix')
3043 if out_of_date_ok:
3044 args.append('--out-of-date-ok')
3045 self._maybe_commit_version(version, args)
3046 if file_list is not None:
3047 file_list = tuple(file_list)
3048 assert 0 < len(file_list)
3049 args.append('--')
3050 args.extend(map(str, file_list))
3051 iterator = backend.sequence_cmd(args, chdir=str(self),
3052 stderr_too=stderr_too)
3053 return classify_changeset_creation(iterator)
3054
3063
3065 """Default log-message object used by import and commit.
3066
3067 If `create` is False, and the standard log file does not already
3068 exists, return None. If `create` is True, use ``tla make-log`` if
3069 needed.
3070 """
3071 path = self._message_path()
3072 if not os.path.exists(path):
3073 if not create: return None
3074 _arch.make_log(self)
3075 return LogMessage(path)
3076
3081
3086
3091
3093 """Replay changesets into this working tree."""
3094 _arch.replay(self)
3095
3097 """Apply delta of new revisions in the archive.
3098
3099 Apply delta(A,B) on this working tree, where A and B are both
3100 revisions of the tree version, A is the latest whose patchlog
3101 is present in the tree and B is the latest present in the
3102 archive.
3103 """
3104 _arch.update(self)
3105
3107 """Pristines present in that source tree.
3108
3109 :return: Revisions which have pristine trees in that source tree.
3110 :rtype: iterable of `Revision`
3111 """
3112 for rvsn in _arch.iter_pristines(self):
3113 yield Revision(rvsn)
3114
3116 """Ensure that the project tree has a particular pristine revision.
3117
3118 :param revision: revision to add a pristine for.
3119 :type revision: `Revision`
3120 """
3121 revision = _revision_param(revision)
3122 _arch.add_pristine(self, revision)
3123
3137
3138
3139
3149
3150
3152
3154 args = ['import', '--dir', tree, '--setup']
3155 if log is not None:
3156 args.extend(('--log', log))
3157 backend.null_cmd(args)
3158
3159 import_ = staticmethod(import_)
3160
3162 args = ('changes', '--dir', tree, '--quiet')
3163 return 1 == backend.status_cmd(args, expected=(0,1))
3164
3165 has_changes = staticmethod(has_changes)
3166
3167 commit_just_commit = []
3168
3170 args = ['star-merge']
3171 if diff3:
3172 args.append('--three-way')
3173 return args
3174
3175 star_merge_args = staticmethod(star_merge_args)
3176
3179
3180 commit_version_args = staticmethod(commit_version_args)
3181
3182
3184
3186 args = ['import', '--dir', tree]
3187 if log is not None:
3188 args.extend(('--log', log))
3189 backend.null_cmd(args)
3190
3191 import_ = staticmethod(import_)
3192
3194 args = ('diff', '--dir', tree, '--quiet', '--summary')
3195 return 1 == backend.status_cmd(args, expected=(0,1))
3196
3197 has_changes = staticmethod(has_changes)
3198
3199 commit_just_commit = ['--just-commit']
3200
3202 args = ['merge', '--star-merge']
3203 if not diff3:
3204 args.append('--two-way')
3205 return args
3206
3207 star_merge_args = staticmethod(star_merge_args)
3208
3209
3211
3213
3214 args = ['import']
3215 if log is not None:
3216 args.extend(('--log', log))
3217 backend.null_cmd(args, chdir=tree)
3218
3219 import_ = staticmethod(import_)
3220
3221
3223
3226
3227 commit_version_args = staticmethod(commit_version_args)
3228
3229
3230
3231
3232 from _changeset import *
3233
3234 public('Changeset')
3235 public('ChangesetApplication', 'ChangesetCreation')
3236 public('delta', 'iter_delta')
3237
3238 public('changeset')
3239
3248
3249
3251 """Internal argument checking utility"""
3252 if not isinstance(param, basestring):
3253 raise TypeError("Parameter \"%s\" must be a string"
3254 " but was: %r" % (name, param))
3255
3257 """Internal argument checking utility"""
3258 if not isinstance(param, WorkingTree):
3259 raise TypeError("Parameter \"%s\" must be a WorkingTree"
3260 " but was: %r" % (name, param))
3261
3262
3263
3264
3265 public('my_id', 'set_my_id', 'make_archive', 'register_archive')
3266
3267 from _my_id import my_id
3268 from _my_id import set_my_id
3269
3270 -def make_archive(name, location, signed=False, listing=False, tla=False):
3271 """Deprecated.
3272
3273 :see: `ArchiveLocation.create_master`
3274
3275 :param name: archive name (e.g. "david@allouche.net--2003b").
3276 :type name: `Archive` or str
3277 :param location: URL of the archive
3278 :type location: str
3279 :param signed: create GPG signatures for the archive contents.
3280 :type signed: bool
3281 :param listing: maintains ''.listing'' files to enable HTTP access.
3282 :type listing: bool
3283 :param tla: create a tla archive instead of a baz archive.
3284 :type tla: bool
3285
3286 :return: an `Archive` instance for the given name.
3287 :rtype: `Archive`
3288
3289 :raise errors.NamespaceError: ``name`` is not a valid archive name.
3290 """
3291 deprecated_callable(make_archive, ArchiveLocation.create_master)
3292 name = _archive_param(name)
3293 archive = Archive(_unsafe((name,)))
3294 params = ArchiveLocationParams()
3295 params.signed = signed
3296 params.listing = listing
3297 if tla:
3298 params.tla_format()
3299 location = ArchiveLocation(location)
3300 location.create_master(archive, params)
3301 return archive
3302
3304 """Deprecated.
3305
3306 :see: `ArchiveLocation.register`
3307
3308 :param name: archive name, or None to use the official name stored in the
3309 archive.
3310 :type name: str, None
3311 :param location: URL of the archive.
3312 :type location: str
3313 :return: newly registered archive.
3314 :rtype: `Archive`.
3315 """
3316 deprecated_callable(register_archive, ArchiveLocation.register)
3317 if name is not None:
3318 name = _archive_param(name)
3319 if Archive(name).is_registered():
3320 raise ValueError('%r is already a registered name' % (name,))
3321
3322 _check_str_param(location, 'location')
3323 return _archive_impl().register_archive(name, location)
3324
3325
3326 public('iter_archives', 'archives')
3327
3329 """Iterate over registered archives.
3330
3331 :return: all registered archives.
3332 :rtype: iterable of `Archive`
3333 """
3334 for n in backend.sequence_cmd(('archives', '--names')):
3335 yield Archive(_unsafe((n,)))
3336
3337
3348
3349
3350 public('iter_library_archives', 'library_archives')
3351
3353 """Iterate over archives present in the revision library.
3354
3355 :returns: all archives which are present in the revision library.
3356 :rtype: iterable of `Archive`
3357 """
3358 for n in _arch.library_archives():
3359 yield Archive(_unsafe((n,)))
3360
3361
3372
3373
3374 public('default_archive')
3375
3377 """Default Archive object or None.
3378
3379 :return: the default archive, or None.
3380 :rtype: `Archive`, None
3381 """
3382 name = _arch.default_archive()
3383 if name is None:
3384 return None
3385 else:
3386 return Archive(_unsafe((name,)))
3387
3388
3389 public('make_continuation')
3390
3400
3401 public('get', 'get_patch')
3402
3403 -def get(revision, dir, link=False):
3404 """ Construct a project tree for a revision.
3405
3406 :rtype: `WorkingTree`
3407 :see: `Revision.get`
3408 """
3409
3410 revision = _package_revision_param(revision)
3411 args = ['get']
3412 if link:
3413 args.append('--link')
3414 args.extend((revision, str(dir)))
3415 backend.null_cmd(args)
3416 return WorkingTree(dir)
3417
3428
3429
3430 public(
3431 'iter_revision_libraries',
3432 'register_revision_library',
3433 'unregister_revision_library',
3434 )
3435
3437 """Iterate over registered revision library directories.
3438
3439 :return: directory names of all registered revision libraries.
3440 :rtype: iterable of str
3441 """
3442 return _arch.iter_revision_libraries()
3443
3445 """Register an existing revision library directory.
3446
3447 :param dirname: absolute path name of existing user-writable directory.
3448 :type dirname: str
3449 :todo: create_revision_library which abstracts out revlib construction.
3450 :postcondition: ``dirname`` is present in `iter_revision_libraries` output.
3451 """
3452 if not os.path.isabs(dirname):
3453 raise ValueError, "not an absolute path: %r" % dirname
3454 if not os.path.isdir(dirname):
3455 raise ValueError, "directory does not exist: %r" % dirname
3456 _arch.register_revision_library(dirname)
3457
3459 """Unregister a revision library directory.
3460
3461 :param dirname: registered revision library directory.
3462 :type dirname: str
3463 :todo: delete_revision_library which abstracts out revlib destruction.
3464 :precondition: ``dirname`` is present in `iter_revision_libraries` output.
3465 :postcondition: ``dirname`` is not listed by `iter_revision_libraries`.
3466 """
3467 if not os.path.isabs(dirname):
3468 raise ValueError, "not an absolute path: %r" % dirname
3469 _arch.unregister_revision_library(dirname)
3470
3471
3472
3473
3474 public('NameParser')
3475
3476 from _nameparser import NameParser
3477
3478
3479
3480
3481 public(
3482 'filter_archive_logs',
3483 'filter_revisions',
3484 'grep_summary',
3485 'grep_summary_interactive',
3486 'suspected_move',
3487 'revisions_merging',
3488 'temphack',
3489 'revision_which_created',
3490 'last_revision',
3491 'map_name_id',
3492 )
3493
3494 from _deprecated_helpers import *
3495