1 # Copyright (C) 2006-2009 Movial Creative Technologies Inc.
3 # Daniel Bainton <daniel.bainton@movial.com>
8 from sets import Set as set
11 from config import config
12 from repositories import Repository
16 class Component(object):
22 rebuild_checked = False
25 def __init__(self, name, branch=None, flags=[], rank=0):
28 self.source = Repository(
30 os.path.join(config.top_dir, 'src', name),
34 self.meta = Repository(
36 os.path.join(config.top_dir, 'src', name, 'meta'),
47 return str(self.source)
50 if self.__dirty is None:
51 for repo in (self.source, self.meta):
56 if self.__dirty is None:
61 def add_depend(self, c):
62 if self.rank < c.rank:
65 print 'Rank fixup:', c, 'inherits rank from', self
66 for dep in c.get_depends():
71 def remove_depend(self, c):
72 self.depends.remove(c)
73 return not self.depends
75 def get_depends(self):
78 def get_licenses(self):
80 for p in self.packages.values():
84 class PlatformProvidedComponent(Component):
85 """A Component that is provided by the platform.
86 The sources will not be built during install."""
94 by_name = Resolver().resolve(targets)
96 class Resolver(object):
101 def resolve(self, targets):
102 # add target components before dependencies so that all custom
103 # Component() arguments will come into effect
106 # target might be an automatic component, those
107 # will be added after the dep resolving stage
110 self.add_component(config.components[name])
114 # if there's no targets, add all manually defined components
116 for c in config.components.itervalues():
117 self.add_component(c)
119 # Otherwise, only look for components with non-zero rank
120 for c in config.components.itervalues():
122 self.add_component(c)
124 # iterate over a _copy_ of the _current_ package list;
125 # automatic components' dependencies will be initialized
126 # recursively as we go.
128 for p in self.packages.values():
129 self.init_package_depends(p)
132 if name not in self.components:
133 self.add_automatic_component(name)
135 self.init_rank_depends()
138 return self.components
140 def add_component(self, c):
141 if not c.meta.exists():
143 c.source.fetch_hash()
147 for path in glob(os.path.join(c.meta.path, '*.package')):
148 name = os.path.basename(path)[:-8]
149 self.add_package(c, name, path)
152 print 'Component', c.name, 'provides', name
157 path = os.path.join(c.meta.path, 'info')
158 if os.path.exists(path):
159 self.add_package(c, c.name, path)
161 self.add_package(c, c.name)
163 self.components[c.name] = c
165 def add_package(self, c, name, path=None):
166 p = parse_package(name, c, path)
169 self.packages[name] = p
171 def init_package_depends(self, p):
172 for spec in to_seq(p.depends):
173 depname = Dependency(spec).name
174 deppkg = self.packages.get(depname)
178 if deppkg.component != p.component:
179 depcomp = deppkg.component
181 depcomp = self.add_automatic_component(depname)
183 log.error('Package %s depends on ' \
184 'non-existent package %s' % \
188 p.component.add_depend(depcomp)
190 def add_automatic_component(self, name):
192 print 'Looking for automatic component:', name
194 # There might be config options for the component
196 c = config.components[name]
200 if not c.meta.exists():
207 self.add_component(c)
209 for p in c.packages.values():
210 self.init_package_depends(p)
214 def init_rank_depends(self):
216 for c in self.components.itervalues():
217 l = by_rank.get(c.rank)
223 ranks = by_rank.keys()
226 for i in xrange(1, len(ranks)):
228 for curr_comp in by_rank[curr_rank]:
231 for prev_comp in by_rank[prev_rank]:
232 curr_comp.add_depend(prev_comp)
234 def check_depends(self):
236 for p in self.packages.itervalues():
237 for spec in to_seq(p.depends):
238 if not Dependency(spec).check(self.packages):
240 log.error('Dependency %s failed for %s' % \
243 for spec in to_seq(p.conflicts):
244 if Dependency(spec).check(self.packages):
246 log.error('Package %s conflicts with %s' % \
250 raise Error('Invalid component tree')
252 class Package(object):
253 def __init__(self, name, component):
255 self.component = component
258 self.conflicts = None
259 self.architectures = None
260 self.license = 'Unknown'
265 if isinstance(value, str):
269 def parse_package(name, component, path=None):
270 p = Package(name, component)
273 execfile(path, p.__dict__, p.__dict__)
276 arch = config.boards[config.board].arch
277 if arch not in p.architectures:
282 class Dependency(object):
283 regex = re.compile(r'([@]?)([^\s:]+)[:]?([<>=]*)([^\s:]*)[:]?(.*)')
285 def __init__(self, spec):
286 match = self.regex.match(spec)
288 raise Error('Bad dependency specification: ' + spec)
290 self.build, self.name, self.tag_op, self.tag, flags \
292 self.flags = flags.split()
294 def check(self, packages):
295 # TODO: check version and flags
296 return self.name in packages
298 def fill_in_depends(components):
304 for dep in c.get_depends():
305 if dep not in components:
308 components |= depends