1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """
23 parsing of registry, which holds component and bundle information
24 """
25
26 import os
27 import stat
28 import errno
29 from StringIO import StringIO
30
31 from xml.dom import minidom, Node
32 from xml.parsers import expat
33
34 from flumotion.common import common, log, package, bundle, errors, fxml
35 from flumotion.configure import configure
36
37 __all__ = ['ComponentRegistry', 'registry']
38
40 return os.stat(file)[stat.ST_MTIME]
41
43 """
44 I represent a <component> entry in the registry
45 """
46
47
48 __pychecker__ = 'maxargs=14'
49
50 - def __init__(self, filename, type,
51 source, description, base, properties, files,
52 entries, eaters, feeders, needs_sync, clock_priority,
53 sockets):
54 """
55 @param filename: name of the XML file this component is parsed from
56 @type filename: str
57 @param properties: dict of name -> property
58 @type properties: dict of str -> L{RegistryEntryProperty}
59 @param entries: dict of entry point type -> entry
60 @type entries: dict of str -> L{RegistryEntryEntry}
61 @param sockets: list of sockets supported by the element
62 @type sockets: list of str
63 """
64 self.filename = filename
65 self.type = type
66 self.source = source
67 self.description = description
68
69 if not self.description:
70 self.description = ""
71 self.base = base
72 self.properties = properties
73 self.files = files
74 self.entries = entries
75 self.eaters = eaters
76 self.feeders = feeders
77 self.needs_sync = needs_sync
78 self.clock_priority = clock_priority
79 self.sockets = sockets
80
81 - def getProperties(self):
82 """
83 Get a list of all properties.
84
85 @rtype: list of L{RegistryEntryProperty}
86 """
87 return self.properties.values()
88
89 - def hasProperty(self, name):
90 """
91 Check if the component has a property with the given name.
92 """
93 return name in self.properties.keys()
94
97
98 - def getEntries(self):
99 return self.entries.values()
100
101 - def getEntryByType(self, type):
102 """
103 Get the entry point for the given type of entry.
104
105 @type type: string
106 """
107 return self.entries[type]
108
109 - def getGUIEntry(self):
110 if not self.files:
111 return
112
113
114 if len(self.files) > 1:
115 return
116
117 return self.files[0].getFilename()
118
121
124
125 - def getDescription(self):
126 return self.description
127
128 - def getSource(self):
130
131 - def getEaters(self):
133
134 - def getFeeders(self):
136
138 return self.needs_sync
139
141 return self.clock_priority
142
143 - def getSockets(self):
145
147 """
148 I represent a <plug> entry in the registry
149 """
150
151 - def __init__(self, filename, type, socket, entry, properties):
152 """
153 @param filename: name of the XML file this plug is parsed from
154 @type filename: str
155 @param type: the type of plug
156 @type type: str
157 @param socket: the fully qualified class name of the socket this
158 plug can be plugged in to
159 @type socket: str
160 @param entry: entry point for instantiating the plug
161 @type entry: L{RegistryEntryEntry}
162 @param properties: properties of the plug
163 @type properties: dict of str -> L{RegistryEntryProperty}
164 """
165 self.filename = filename
166 self.type = type
167 self.socket = socket
168 self.entry = entry
169 self.properties = properties
170
171 - def getProperties(self):
172 """
173 Get a list of all properties.
174
175 @rtype: list of L{RegistryEntryProperty}
176 """
177 return self.properties.values()
178
179 - def hasProperty(self, name):
180 """
181 Check if the component has a property with the given name.
182 """
183 return name in self.properties.keys()
184
185 - def getEntry(self):
187
190
191 - def getSocket(self):
193
195 "This class represents a <bundle> entry in the registry"
196 - def __init__(self, name, project, under, dependencies, directories):
197 self.name = name
198 self.project = project
199 self.under = under
200 self.dependencies = dependencies
201 self.directories = directories
202
203 - def __repr__(self):
204 return '<Bundle name=%s>' % self.name
205
208
209 - def getDependencies(self):
210 return self.dependencies
211
212 - def getDirectories(self):
213 return self.directories
214
215 - def getProject(self):
217
218 - def getUnder(self):
220
221 - def getBaseDir(self):
222 if self.project == 'flumotion':
223 return getattr(configure, self.under)
224
225 from flumotion.project import project
226 return project.get(self.project, self.under)
227
229 "This class represents a <directory> entry in the registry"
230 - def __init__(self, name, files):
231 self.name = name
232 self.files = files
233
236
237 - def getFiles(self):
239
241 "This class represents a <filename> entry in the registry"
242 - def __init__(self, location, relative):
243 self.location = location
244 self.relative = relative
245
246 - def getLocation(self):
248
249 - def getRelative(self):
251
253 "This class represents a <property> entry in the registry"
254 - def __init__(self, name, type, description, required=False, multiple=False):
255 self.name = name
256 self.type = type
257 self.description = description
258
259 if not self.description:
260 self.description = ""
261 self.required = required
262 self.multiple = multiple
263
264 - def __repr__(self):
265 return '<Property name=%s>' % self.name
266
269
272
273 - def getDescription(self):
274 return self.description
275
276 - def isRequired(self):
278
279 - def isMultiple(self):
281
283 "This class represents a <file> entry in the registry"
284 - def __init__(self, filename, type):
285 self.filename = filename
286 self.type = type
287
289 return os.path.basename(self.filename)
290
293
294 - def getFilename(self):
296
297 - def isType(self, type):
298 return self.type == type
299
301 "This class represents a <entry> entry in the registry"
302 - def __init__(self, type, location, function):
303 self.type = type
304 self.location = location
305 self.function = function
306
309
310 - def getLocation(self):
312
313 - def getModuleName(self, base=None):
314 if base:
315 path = os.path.join(base, self.getLocation())
316 else:
317 path = self.getLocation()
318 return common.pathToModuleName(path)
319
320 - def getFunction(self):
322
324 "This class represents a <eater> entry in the registry"
325 - def __init__(self, name, required=True, multiple=False):
326 self.name = name
327 self.required = required
328 self.multiple = multiple
329
332
333 - def getRequired(self):
335
336 - def getMultiple(self):
338
340 """
341 Registry parser
342
343 I have two modes, one to parse registries and another one to parse
344 standalone component files.
345
346 For parsing registries use the parseRegistry function and for components
347 use parseRegistryFile.
348
349 I also have a list of all components and directories which the
350 registry uses (instead of saving its own copy)
351 """
352
355
357 self._components = {}
358 self._directories = {}
359 self._bundles = {}
360 self._plugs = {}
361
363 return self._components.values()
364
366 return self._components[name]
367
369 return self._plugs.values()
370
372 return self._plugs[name]
373
375
376
377
378
379 components = {}
380 def addComponent(comp):
381 components[comp.getType()] = comp
382
383 parsers = {'component': (self._parseComponent, addComponent)}
384 self.parseFromTable(node, parsers)
385
386 return components
387
389
390
391
392
393
394
395
396
397
398
399
400 type, baseDir, description = self.parseAttributes(node,
401 required=('type', ), optional=('base', 'description'))
402
403 files = []
404 source = fxml.Box(None)
405 entries = {}
406 eaters = []
407 feeders = []
408 synchronization = fxml.Box((False, 100))
409 sockets = []
410 properties = {}
411
412
413 if node.hasAttribute('inherit'):
414 base_type = str(node.getAttribute('inherit'))
415 base = self.getComponent(base_type)
416 for prop in base.getProperties():
417 properties[prop.getName()] = prop
418
419 parsers = {
420 'source': (self._parseSource, source.set),
421 'properties': (self._parseProperties, properties.update),
422 'files': (self._parseFiles, files.extend),
423 'entries': (self._parseEntries, entries.update),
424 'eater': (self._parseEater, eaters.append),
425 'feeder': (self._parseFeeder, feeders.append),
426 'synchronization': (self._parseSynchronization,
427 synchronization.set),
428 'sockets': (self._parseSockets, sockets.extend),
429 }
430
431 self.parseFromTable(node, parsers)
432
433 source = source.unbox()
434 needs_sync, clock_priority = synchronization.unbox()
435
436 return RegistryEntryComponent(self.filename,
437 type, source, description, baseDir,
438 properties, files,
439 entries, eaters, feeders,
440 needs_sync, clock_priority,
441 sockets)
442
447
449
450
451
452 attrs = self.parseAttributes(node, required=('name', 'type'),
453 optional=('required', 'multiple', 'description'))
454 name, type, required, multiple, description = attrs
455 required = common.strToBool(required)
456 multiple = common.strToBool(multiple)
457 return RegistryEntryProperty(name, type, description, required=required,
458 multiple=multiple)
459
468
469 parsers = {'property': (self._parseProperty, addProperty)}
470
471 self.parseFromTable(node, parsers)
472
473 return properties
474
483
495
502
514
515 - def _parseEntry(self, node):
516 attrs = self.parseAttributes(node, ('type', 'location', 'function'))
517 type, location, function = attrs
518 return RegistryEntryEntry(type, location, function)
519
521
522
523
524
525
526 entries = {}
527 def addEntry(entry):
528 if entry.getType() in entries:
529 raise fxml.ParserError("entry %s already specified"
530 % entry.getType())
531 entries[entry.getType()] = entry
532
533 parsers = {'entry': (self._parseEntry, addEntry)}
534
535 self.parseFromTable(node, parsers)
536
537 return entries
538
548
553
555
556 attrs = self.parseAttributes(node, (), ('required', 'clock-priority'))
557 required, clock_priority = attrs
558 required = common.strToBool(required)
559 clock_priority = int(clock_priority or '100')
560 return required, clock_priority
561
562 - def _parsePlugEntry(self, node):
563
564
565
566 attrs = self.parseAttributes(node, ('location', 'function'))
567 location, function = attrs
568 return RegistryEntryEntry('plug', location, function)
569
571
572
573
574
575
576 type, socket = self.parseAttributes(node, ('type', 'socket'))
577
578 entry = fxml.Box(None)
579 properties = {}
580
581 parsers = {'entry': (self._parsePlugEntry, entry.set),
582 'properties': (self._parseProperties, properties.update)}
583
584 self.parseFromTable(node, parsers)
585
586 if not entry.unbox():
587 raise fxml.ParserError("<plug> %s needs an <entry>" % type)
588
589 return RegistryEntryPlug(self.filename, type,
590 socket, entry.unbox(), properties)
591
602
603 parsers = {'plug': (self._parsePlug, addPlug)}
604 self.parseFromTable(node, parsers)
605
606 return plugs
607
608
610 """
611 @param file: The file to parse, either as an open file object,
612 or as the name of a file to open.
613 @type file: str or file.
614 """
615 self.filename = getattr(file, 'name', '<string>')
616 root = self.getRoot(file)
617 node = root.documentElement
618
619 if node.nodeName != 'registry':
620
621
622 self.debug('%s does not have registry as root tag' % self.filename)
623 return
624
625
626 self._parseRoot(node, disallowed=['directories'])
627
629
630
631
632
633 bundles = {}
634 def addBundle(bundle):
635 bundles[bundle.getName()] = bundle
636
637 parsers = {'bundle': (self._parseBundle, addBundle)}
638 self.parseFromTable(node, parsers)
639
640 return bundles
641
643
644
645
646
647
648 attrs = self.parseAttributes(node, ('name',), ('project', 'under'))
649 name, project, under = attrs
650 project = project or 'flumotion'
651 under = under or 'pythondir'
652
653 dependencies = []
654 directories = []
655
656 parsers = {'dependencies': (self._parseBundleDependencies,
657 dependencies.extend),
658 'directories': (self._parseBundleDirectories,
659 directories.extend)}
660 self.parseFromTable(node, parsers)
661
662 return RegistryEntryBundle(name, project, under, dependencies, directories)
663
667
679
691
700
710
711 parsers = {'filename': (parseFilename, filenames.append)}
712 self.parseFromTable(node, parsers)
713
714 return RegistryEntryBundleDirectory(name, filenames)
715
716
718 """
719 @param file: The file to parse, either as an open file object,
720 or as the name of a file to open.
721 @type file: str or file.
722 """
723 self.filename = getattr(file, 'name', '<string>')
724 root = self.getRoot(file)
725 self._parseRoot(root.documentElement)
726
728 return self._directories.values()
729
731 return self._directories[name]
732
734 """
735 Add a registry path object to the parser.
736
737 @type directory: {RegistryDirectory}
738 """
739 self._directories[directory.getPath()] = directory
740
742 """
743 Remove a directory from the parser given the path.
744 Used when the path does not actually contain any registry information.
745 """
746 if path in self._directories.keys():
747 del self._directories[path]
748
766
768
769
770
771
772 directories = {}
773 def addDirectory(d):
774 directories[d.getPath()] = d
775
776 parsers = {'directory': (self._parseDirectory, addDirectory)}
777 self.parseFromTable(node, parsers)
778
779 return directories
780
785
786
787
789 """
790 I represent a directory under a path managed by the registry.
791 I can be queried for a list of partial registry .xml files underneath
792 the given path, under the given prefix.
793 """
794 - def __init__(self, path, prefix='flumotion'):
798
800 return "<RegistryDirectory %s>" % self._path
801
803 """
804 Get all files ending in .xml from all directories under the given root.
805
806 @type root: string
807 @param root: the root directory under which to search
808
809 @returns: a list of .xml files, relative to the given root directory
810 """
811 files = []
812
813 if os.path.exists(root):
814 try:
815 directory_files = os.listdir(root)
816 except OSError, e:
817 if e.errno == errno.EACCES:
818 return files
819 else:
820 raise
821
822 for dir in directory_files:
823 filename = os.path.join(root, dir)
824
825 if not os.path.isdir(filename):
826 if filename.endswith('.xml'):
827 files.append(filename)
828
829 else:
830 files += self._getFileList(filename)
831
832 return files
833
835 assert self._files, "Path %s does not have registry files" % self._path
836 return max(map(_getMTime, self._files))
837
839 """
840 Return a list of all .xml registry files underneath this registry
841 path.
842 """
843 return self._files
844
847
849 - def __init__(self, components, plugs, bundles, directories):
850 """
851 @param components: components to write
852 @type components: list of L{RegistryEntryComponent}
853 @param plugs: plugs to write
854 @type plugs: list of L{RegistryEntryPlug}
855 @param bundles: bundles to write
856 @type bundles: list of L{RegistryEntryBundle}
857 @param directories: directories to write
858 @type directories: list of L{RegistryEntryDirectory}
859 """
860 self.components = components
861 self.plugs = plugs
862 self.bundles = bundles
863 self.directories = directories
864
865 - def dump(self, fd):
866 """
867 Dump the cache of components to the given opened file descriptor.
868
869 @type fd: integer
870 @param fd: open file descriptor to write to
871 """
872
873 def w(i, msg):
874 print >> fd, ' '*i + msg
875
876 w(0, '<registry>')
877 w(0, '')
878
879
880 w(2, '<components>')
881 w(0, '')
882 for component in self.components:
883 w(4, '<component type="%s" base="%s"' % (
884 component.getType(), component.getBase()))
885 w(4, ' description="%s">' % component.getDescription())
886
887 w(6, '<source location="%s"/>' % component.getSource())
888 for x in component.getEaters():
889 w(6, '<eater name="%s" required="%s" multiple="%s"/>'
890 % (x.getName(), x.getRequired() and "yes" or "no",
891 x.getMultiple() and "yes" or "no"))
892 for x in component.getFeeders():
893 w(6, '<feeder name="%s"/>' % x)
894 w(6, '<synchronization required="%s" clock-priority="%d"/>'
895 % (component.getNeedsSynchronization() and "yes" or "no",
896 component.getClockPriority()))
897
898 sockets = component.getSockets()
899 if sockets:
900 w(6, '<sockets>')
901 for socket in sockets:
902 w(8, '<socket type="%s"/>' % socket)
903 w(6, '</sockets>')
904
905 w(6, '<properties>')
906 for prop in component.getProperties():
907 w(8, ('<property name="%s" type="%s"'
908 % (prop.getName(), prop.getType())))
909 w(8, (' description="%s"'
910 % (prop.getDescription(),)))
911 w(8, (' required="%s" multiple="%s"/>'
912 % (prop.isRequired(), prop.isMultiple())))
913 w(6, '</properties>')
914
915 files = component.getFiles()
916 if files:
917 w(6, '<files>')
918 for file in files:
919 w(8, '<file name="%s" type="%s"/>' % (
920 file.getName(),
921 file.getType()))
922 w(6, '</files>')
923
924 entries = component.getEntries()
925 if entries:
926 w(6, '<entries>')
927 for entry in entries:
928 w(8, '<entry type="%s" location="%s" function="%s"/>' % (
929 entry.getType(),
930 entry.getLocation(),
931 entry.getFunction()))
932 w(6, '</entries>')
933 w(4, '</component>')
934 w(0, '')
935
936 w(2, '</components>')
937 w(0, '')
938
939
940 w(2, '<plugs>')
941 w(0, '')
942 for plug in self.plugs:
943 w(4, '<plug type="%s" socket="%s">'
944 % (plug.getType(), plug.getSocket()))
945
946 entry = plug.getEntry()
947 w(6, ('<entry location="%s" function="%s"/>'
948 % (entry.getLocation(), entry.getFunction())))
949
950 w(6, '<properties>')
951 for prop in plug.getProperties():
952 w(8, ('<property name="%s" type="%s"' % (
953 prop.getName(), prop.getType())))
954 w(8, (' description="%s"' % prop.getDescription()))
955 w(8, (' required="%s" multiple="%s"/>' % (
956 prop.isRequired(), prop.isMultiple())))
957 w(6, '</properties>')
958
959 w(4, '</plug>')
960 w(0, '')
961
962 w(2, '</plugs>')
963 w(0, '')
964
965
966 w(2, '<bundles>')
967 for bundle in self.bundles:
968 w(4, '<bundle name="%s" under="%s" project="%s">' % (
969 bundle.getName(), bundle.getUnder(), bundle.getProject()))
970
971 dependencies = bundle.getDependencies()
972 if dependencies:
973 w(6, '<dependencies>')
974 for dependency in dependencies:
975 w(8, '<dependency name="%s"/>' % dependency)
976 w(6, '</dependencies>')
977
978 dirs = bundle.getDirectories()
979 if dirs:
980 w(6, '<directories>')
981 for dir in dirs:
982 w(8, '<directory name="%s">' % dir.getName())
983 for filename in dir.getFiles():
984 w(10, '<filename location="%s" relative="%s"/>' % (
985 filename.getLocation(), filename.getRelative()))
986 w(8, '</directory>')
987 w(6, '</directories>')
988
989 w(4, '</bundle>')
990 w(0, '')
991 w(2, '</bundles>')
992
993
994
995 directories = self.directories
996 if directories:
997 w(2, '<directories>')
998 w(0, '')
999 for d in directories:
1000 w(4, '<directory filename="%s"/>' % d.getPath())
1001 w(2, '</directories>')
1002 w(0, '')
1003
1004 w(0, '</registry>')
1005
1007 """Registry, this is normally not instantiated."""
1008
1009 logCategory = 'registry'
1010 filename = os.path.join(configure.registrydir, 'registry.xml')
1011
1029
1031 """
1032 @param file: The file to add, either as an open file object, or
1033 as the name of a file to open.
1034 @type file: str or file.
1035 """
1036 if isinstance(file, str) and file.endswith('registry.xml'):
1037 self.warning('%s seems to be an old registry in your tree, '
1038 'please remove it', file)
1039 self.debug('Adding file: %r', file)
1040 self._parser.parseRegistryFile(file)
1041
1043 f = StringIO(string)
1044 self.addFile(f)
1045 f.close()
1046
1048 """
1049 Add a registry path to this registry, scanning it for registry
1050 snippets.
1051
1052 @param path: a full path containing a 'flumotion' directory,
1053 which will be scanned for registry files.
1054
1055 @rtype: bool
1056 @returns: whether the path could be added
1057 """
1058 self.debug('path %s, prefix %s' % (path, prefix))
1059 if not os.path.exists(path):
1060 self.warning("Cannot add non-existent path '%s' to registry" % path)
1061 return False
1062 if not os.path.exists(os.path.join(path, prefix)):
1063 self.warning("Cannot add path '%s' to registry "
1064 "since it does not contain prefix '%s'" % (path, prefix))
1065 return False
1066
1067
1068
1069 self.info('Scanning registry path %s' % path)
1070 registryPath = RegistryDirectory(path, prefix=prefix)
1071 files = registryPath.getFiles()
1072 self.debug('Found %d possible registry files' % len(files))
1073 map(self.addFile, files)
1074
1075 self._parser.addDirectory(registryPath)
1076 return True
1077
1079 return len(self._parser._components) == 0
1080
1082 """
1083 @rtype: L{RegistryEntryComponent}
1084 """
1085 return self._parser._components[name]
1086
1088 return self._parser._components.has_key(name)
1089
1091 return self._parser._components.values()
1092
1094 """
1095 @rtype: L{RegistryEntryPlug}
1096 """
1097 return self._parser._plugs[type]
1098
1100 return self._parser._plugs.has_key(name)
1101
1103 return self._parser._plugs.values()
1104
1106 return self._parser._bundles.values()
1107
1110
1112 """
1113 @rtype: L{flumotion.common.bundle.BundlerBasket}
1114 """
1115 def load():
1116 ret = bundle.BundlerBasket()
1117 for b in self.getBundles():
1118 bundleName = b.getName()
1119 self.debug('Adding bundle %s' % bundleName)
1120 for d in b.getDirectories():
1121 directory = d.getName()
1122 for file in d.getFiles():
1123 try:
1124 basedir = b.getBaseDir()
1125 except errors.NoProjectError, e:
1126 self.warning("Could not find project %s" % e.args)
1127 raise
1128 fullpath = os.path.join(basedir, directory,
1129 file.getLocation())
1130 relative = file.getRelative()
1131 self.log('Adding path %s as %s to bundle %s' % (
1132 fullpath, relative, bundleName))
1133 try:
1134 ret.add(bundleName, fullpath, relative)
1135 except Exception, e:
1136 self.debug("Reason: %r" % e)
1137 raise RuntimeError(
1138 'Could not add %s to bundle %s (%s)'
1139 % (fullpath, bundleName, e))
1140 for d in b.getDependencies():
1141 self.log('Adding dependency of %s on %s' % (bundleName, d))
1142 ret.depend(bundleName, d)
1143 return ret
1144
1145 try:
1146 return load()
1147 except Exception, e:
1148 self.warning("Bundle problem, rebuilding registry (%s)" % e)
1149 self.verify(force=True)
1150 try:
1151 return load()
1152 except Exception, e:
1153 self.debug("Could not register bundles twice: %s" %
1154 log.getExceptionMessage(e))
1155 self.error("Could not not register bundles (%s)" % e)
1156
1157 - def dump(self, fd):
1167
1169 """
1170 Clean the cache of components.
1171 """
1172 self._parser.clean()
1173
1184
1185 - def save(self, force=False):
1186 if not force and not self.rebuildNeeded():
1187 return
1188
1189 self.info('Saving registry to %s' % self.filename)
1190
1191
1192 dir = os.path.split(self.filename)[0]
1193 if not os.path.exists(dir):
1194 try:
1195 os.makedirs(dir)
1196 except OSError, e:
1197 if e.errno == errno.EACCES:
1198 self.error('Registry directory %s could not be created !' %
1199 dir)
1200 else:
1201 raise
1202
1203 if not os.path.isdir(dir):
1204 self.error('Registry directory %s is not a directory !')
1205 try:
1206 fd = open(self.filename, 'w')
1207 self.dump(fd)
1208 except IOError, e:
1209 if e.errno == errno.EACCES:
1210 self.error('Registry file %s could not be created !' %
1211 self.filename)
1212 else:
1213 raise
1214
1215 - def verify(self, force=False):
1216 """
1217 Verify if the registry is uptodate and rebuild if it is not.
1218
1219 @param force: True if the registry needs rebuilding for sure.
1220 """
1221
1222 registryPaths = [configure.pythondir, ]
1223 if os.environ.has_key('FLU_PROJECT_PATH'):
1224 paths = os.environ['FLU_PROJECT_PATH']
1225 registryPaths += paths.split(':')
1226
1227
1228 oldRegistryPaths = [dir.getPath() for dir in self.getDirectories()]
1229
1230 oldRegistryPaths = [p for p in oldRegistryPaths if os.path.exists(p)]
1231
1232 self.debug('previously scanned registry paths: %s' %
1233 ", ".join(oldRegistryPaths))
1234
1235
1236
1237 registryPaths.sort()
1238 oldRegistryPaths.sort()
1239 if registryPaths != oldRegistryPaths:
1240 self.debug('old and new registry paths are different')
1241 self.info('Rescanning registry paths')
1242 force = True
1243 else:
1244 self.debug('registry paths are still the same')
1245
1246
1247
1248
1249 for path in registryPaths:
1250 directory = self._parser._directories.get(path, None)
1251 if directory:
1252
1253
1254 dTime = directory.lastModified()
1255 fTime = _getMTime(self.filename)
1256 if dTime < fTime:
1257 self.debug('%s not changed since last registry parse' %
1258 path)
1259 else:
1260 self.debug('%s has changed since last registry parse' %
1261 path)
1262 force = True
1263
1264 if force:
1265 self.clean()
1266 for path in registryPaths:
1267 if not self.addRegistryPath(path):
1268 self._parser.removeDirectoryByPath(path)
1269
1270 self.save(force)
1271
1273 - def __init__(self, fromRegistry=None, onlyBundles=None):
1274 """
1275 @param fromRegistry: The registry to subset, or the default.
1276 @type fromRegistry: L{ComponentRegistry}
1277 @param onlyBundles: If given, only include the subset of the
1278 registry that is provided by bundles whose names are in this
1279 list.
1280 @type onlyBundles: list of str
1281 """
1282 self.fromRegistry = fromRegistry
1283 self.onlyBundles = onlyBundles
1284
1285 - def dump(self, fd):
1286 reg = self.fromRegistry or getRegistry()
1287 pred = None
1288 if self.onlyBundles is not None:
1289 pred = lambda b: b.name in self.onlyBundles
1290 bundles = filter(pred, reg.getBundles())
1291
1292 bundledfiles = {}
1293 for b in bundles:
1294 for d in b.getDirectories():
1295 for f in d.getFiles():
1296 filename = os.path.join(d.getName(), f.getLocation())
1297 bundledfiles[filename] = b
1298
1299 def fileIsBundled(basedir, filename):
1300 return os.path.join(basedir, filename) in bundledfiles
1301
1302 pred = lambda c: (filter(lambda f: fileIsBundled(c.getBase(),
1303 f.getFilename()),
1304 c.getFiles())
1305 or filter(lambda e: fileIsBundled(c.getBase(),
1306 e.getLocation()),
1307 c.getEntries()))
1308 components = filter(pred, reg.getComponents())
1309
1310 pred = lambda p: p.getEntry().getLocation() in bundledfiles
1311 plugs = filter(pred, reg.getPlugs())
1312
1313 directories = []
1314
1315 regwriter = RegistryWriter(components, plugs, bundles, directories)
1316 regwriter.dump(fd)
1317
1318 __registry = None
1319
1333