diff options
Diffstat (limited to 'scripts/jhbuild/jhbuild2oe.py')
-rwxr-xr-x | scripts/jhbuild/jhbuild2oe.py | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/scripts/jhbuild/jhbuild2oe.py b/scripts/jhbuild/jhbuild2oe.py new file mode 100755 index 0000000000..ef292763de --- /dev/null +++ b/scripts/jhbuild/jhbuild2oe.py | |||
@@ -0,0 +1,278 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # Available modulesets: | ||
3 | # | ||
4 | # bootstrap.modules | ||
5 | # freedesktop.modules | ||
6 | # gcj.modules | ||
7 | # gnome-2.10.modules | ||
8 | # gnome-2.12.modules | ||
9 | # gnome-2.14.modules | ||
10 | # gnome-2.16.modules | ||
11 | # gnutls.modules | ||
12 | # gtk28.modules | ||
13 | # gtk.modules | ||
14 | # xorg-7.0.modules | ||
15 | # xorg.modules | ||
16 | |||
17 | moduleset = 'xorg.modules' | ||
18 | |||
19 | |||
20 | |||
21 | import cElementTree as ElementTree | ||
22 | # import lxml.etree as ElementTree | ||
23 | import re, os, bb, bb.data | ||
24 | |||
25 | class Handlers(object): | ||
26 | """ | ||
27 | Class to act as a store for handlers of jhbuild xml elements, and as a | ||
28 | dispatcher of parsed Elements to those handlers. | ||
29 | |||
30 | These handlers exist to take an xml element from the jhbuild files and | ||
31 | either produce bitbake metadata in self.packages, or produce data which | ||
32 | will be used by other element handlers to do so. | ||
33 | |||
34 | Handlers(filename) -> new object to parse and process jhbuild file of | ||
35 | name 'filename'. | ||
36 | """ | ||
37 | |||
38 | cvsrootpat = re.compile(r''' | ||
39 | \s* # Skip leading whitespace | ||
40 | :(?P<scheme>[^:]+): # scheme (i.e. pserver, ext) | ||
41 | ((?P<user>\S+?)@)? # username | ||
42 | (?P<host>\S+?): # non-greedy match of the remote host | ||
43 | (?P<path>\S+) # remote path | ||
44 | ''', re.VERBOSE) | ||
45 | |||
46 | |||
47 | def __init__(self, msfile): | ||
48 | self.msfile = msfile | ||
49 | self.msbasename = os.path.basename(msfile) | ||
50 | self.msdirname = os.path.dirname(msfile) | ||
51 | |||
52 | self.handled = {} | ||
53 | |||
54 | self.cvsroots = {} | ||
55 | self.repositories = {} | ||
56 | self.packages = [] | ||
57 | |||
58 | def handle(self, element, parent): | ||
59 | import sys | ||
60 | """ | ||
61 | XML Element dispatch function. Can be called both from outside the | ||
62 | Handlers object to initiate handling, and from within individual XML | ||
63 | element handlers to ensure that dependent elements have been handled. | ||
64 | |||
65 | Does not handle a given XML Element more than once, as it retains | ||
66 | information about the handling state of the Elements it encounters. | ||
67 | """ | ||
68 | |||
69 | try: | ||
70 | state = self.handled[element] | ||
71 | except KeyError: | ||
72 | pass | ||
73 | except: | ||
74 | return | ||
75 | |||
76 | try: | ||
77 | self.__class__.__dict__[element.tag](self, element, parent) | ||
78 | self.handled[element] = True | ||
79 | except KeyError: | ||
80 | self.handled[element] = False | ||
81 | sys.__stderr__.write('Unhandled element: %s\n' % element.tag) | ||
82 | except Exception: | ||
83 | sys.__stderr__.write('Error handling %s: %s:\n %s\n' % (element.tag, sys.exc_type, sys.exc_value)) | ||
84 | self.handled[element] = False | ||
85 | |||
86 | print('handle(%s, %s) -> %s' % (element, parent, self.handled[element])) | ||
87 | return self.handled[element] | ||
88 | |||
89 | def cvsroot(self, element, parent): | ||
90 | # Rip apart the cvsroot style location to build a cvs:// url for | ||
91 | # bitbake's usage in the cvsmodule handler. | ||
92 | # root=":pserver:anoncvs@cvs.freedesktop.org:/cvs/fontconfig" | ||
93 | print("cvsroot(%s, %s)" % (element, parent)) | ||
94 | |||
95 | root = element.attrib.get('root') | ||
96 | rootmatch = re.match(Handlers.cvsrootpat, root) | ||
97 | name = element.attrib.get('name') | ||
98 | user = rootmatch.group('user') or '' | ||
99 | if user != '': | ||
100 | pw = element.attrib.get('password') or '' | ||
101 | if pw != '': | ||
102 | pw = ':' + pw + '@' | ||
103 | else: | ||
104 | user = user + '@' | ||
105 | print('user: %s' % user) | ||
106 | print('pw: %s' % pw) | ||
107 | |||
108 | host = rootmatch.group('host') | ||
109 | print('host: %s' % host) | ||
110 | path = rootmatch.group('path') or '/' | ||
111 | print('path: %s' % path) | ||
112 | |||
113 | root = "cvs://%s%s%s%s" % (user, pw, host, path) | ||
114 | print('root: %s' % root) | ||
115 | self.cvsroots[name] = root | ||
116 | |||
117 | def cvsmodule(self, element, parent): | ||
118 | rootlist = [root for root in list(parent) if root.attrib.get('name') == element.attrib.get('cvsroot')] | ||
119 | if len(rootlist) < 1: | ||
120 | raise Exception("Error: cvsmodule '%s' requires cvsroot '%s'." % (element.attrib.get('module'), element.attrib.get('cvsroot'))) | ||
121 | |||
122 | cvsroot = rootlist[0] | ||
123 | |||
124 | |||
125 | def include(self, element, parent): | ||
126 | href = element.attrib.get('href') | ||
127 | fullhref = os.path.join(self.msdirname, href) | ||
128 | tree = ElementTree.ElementTree(file=fullhref) | ||
129 | elem = tree.getroot() | ||
130 | |||
131 | # Append the children of the newly included root element to the parent | ||
132 | # element, and manually handle() them, as the currently running | ||
133 | # iteration isn't going to hit them. | ||
134 | for child in elem: | ||
135 | self.handle(child, elem) | ||
136 | parent.append(elem) | ||
137 | |||
138 | def repository(self, element, parent): | ||
139 | # TODO: | ||
140 | # Convert the URL in the href attribute, if necessary, to the format | ||
141 | # which bitbake expects to see in SRC_URI. | ||
142 | name = element.attrib.get('name') | ||
143 | self.repositories[name] = element.attrib.get('href') | ||
144 | |||
145 | |||
146 | def moduleset(self, element, parent): | ||
147 | for child in element: | ||
148 | self.handle(child, element) | ||
149 | |||
150 | def packagename(self, name): | ||
151 | # mangle name into an appropriate bitbake package name | ||
152 | return name.replace('/', '-') | ||
153 | |||
154 | def metamodule(self, element, parent): | ||
155 | # grab the deps | ||
156 | deps = None | ||
157 | for child in element: | ||
158 | if child.tag == 'dependencies': | ||
159 | deps = [self.packagename(dep.attrib.get('package')) for dep in child if dep.tag == "dep"] | ||
160 | |||
161 | # create the package | ||
162 | d = bb.data.init() | ||
163 | pn = self.packagename(element.attrib.get('id')) | ||
164 | bb.data.setVar('PN', pn, d) | ||
165 | bb.data.setVar('DEPENDS', ' '.join(deps), d) | ||
166 | bb.data.setVar('_handler', 'metamodule', d) | ||
167 | self.packages.append(d) | ||
168 | |||
169 | def autotools(self, element, parent): | ||
170 | deps = None | ||
171 | branch = None | ||
172 | for child in element: | ||
173 | if child.tag == 'dependencies': | ||
174 | deps = [self.packagename(dep.attrib.get('package')) for dep in child if dep.tag == "dep"] | ||
175 | elif child.tag == 'branch': | ||
176 | branch = child | ||
177 | |||
178 | # create the package | ||
179 | d = bb.data.init() | ||
180 | id = element.attrib.get('id') | ||
181 | if id is None: | ||
182 | raise Exception('Error: autotools element has no id attribute.') | ||
183 | pn = self.packagename(id) | ||
184 | bb.data.setVar('PN', pn, d) | ||
185 | if deps is not None: | ||
186 | bb.data.setVar('DEPENDS', ' '.join(deps), d) | ||
187 | |||
188 | if branch is not None: | ||
189 | # <branch repo="git.freedesktop.org" module="xorg/xserver"/> | ||
190 | repo = os.path.join(self.repositories[branch.attrib.get('repo')], branch.attrib.get('module')) | ||
191 | bb.data.setVar('SRC_URI', repo, d) | ||
192 | |||
193 | checkoutdir = branch.attrib.get('checkoutdir') | ||
194 | if checkoutdir is not None: | ||
195 | bb.data.setVar('S', os.path.join('${WORKDIR}', checkoutdir), d) | ||
196 | |||
197 | # build class | ||
198 | bb.data.setVar('INHERITS', 'autotools', d) | ||
199 | bb.data.setVarFlag('INHERITS', 'operator', '+=', d) | ||
200 | bb.data.setVar('_handler', 'autotools', d) | ||
201 | self.packages.append(d) | ||
202 | |||
203 | class Emitter(object): | ||
204 | """ | ||
205 | Class which contains a single method for the emission of a bitbake | ||
206 | package from the bitbake data produced by a Handlers object. | ||
207 | """ | ||
208 | |||
209 | def __init__(self, filefunc = None, basedir = None): | ||
210 | def _defaultfilefunc(package): | ||
211 | # return a relative path to the bitbake .bb which will be written | ||
212 | return bb.data.getVar('PN', package, 1) + '.bb' | ||
213 | |||
214 | self.filefunc = filefunc or _defaultfilefunc | ||
215 | self.basedir = basedir or os.path.abspath(os.curdir) | ||
216 | |||
217 | def write(self, package, template = None): | ||
218 | # 1) Assemble new file contents in ram, either new from bitbake | ||
219 | # metadata, or a combination of the template and that metadata. | ||
220 | # 2) Open the path returned by the filefunc + the basedir for writing. | ||
221 | # 3) Write the new bitbake data file. | ||
222 | fdata = '' | ||
223 | if template: | ||
224 | f = file(template, 'r') | ||
225 | fdata = f.read() | ||
226 | f.close() | ||
227 | |||
228 | for key in bb.data.keys(package): | ||
229 | fdata = fdata.replace('@@'+key+'@@', bb.data.getVar(key, package)) | ||
230 | else: | ||
231 | for key in bb.data.keys(package): | ||
232 | if key == '_handler': | ||
233 | continue | ||
234 | elif key == 'INHERITS': | ||
235 | fdata += 'inherit %s\n' % bb.data.getVar('INHERITS', package) | ||
236 | else: | ||
237 | oper = bb.data.getVarFlag(key, 'operator', package) or '=' | ||
238 | fdata += '%s %s "%s"\n' % (key, oper, bb.data.getVar(key, package)) | ||
239 | |||
240 | if not os.path.exists(os.path.join(self.basedir, os.path.dirname(self.filefunc(package)))): | ||
241 | os.makedirs(os.path.join(self.basedir, os.path.dirname(self.filefunc(package)))) | ||
242 | |||
243 | out = file(os.path.join(self.basedir, self.filefunc(package)), 'w') | ||
244 | out.write(fdata) | ||
245 | out.close() | ||
246 | |||
247 | def _test(): | ||
248 | msfile = os.path.join(os.path.abspath(os.curdir), 'modulesets', moduleset) | ||
249 | tree = ElementTree.ElementTree(file=msfile) | ||
250 | elem = tree.getroot() | ||
251 | |||
252 | handlers = Handlers(msfile) | ||
253 | handlers.handle(elem, None) | ||
254 | |||
255 | def filefunc(package): | ||
256 | # return a relative path to the bitbake .bb which will be written | ||
257 | src_uri = bb.data.getVar('SRC_URI', package, 1) | ||
258 | filename = bb.data.getVar('PN', package, 1) + '.bb' | ||
259 | if not src_uri: | ||
260 | return filename | ||
261 | else: | ||
262 | substr = src_uri[src_uri.find('xorg/'):] | ||
263 | subdirlist = substr.split('/')[:2] | ||
264 | subdir = '-'.join(subdirlist) | ||
265 | return os.path.join(subdir, filename) | ||
266 | |||
267 | emitter = Emitter(filefunc) | ||
268 | for package in handlers.packages: | ||
269 | template = emitter.filefunc(package) + '.in' | ||
270 | if os.path.exists(template): | ||
271 | print("%s exists, emitting based on template" % template) | ||
272 | emitter.write(package, template) | ||
273 | else: | ||
274 | print("%s does not exist, emitting non-templated" % template) | ||
275 | emitter.write(package) | ||
276 | |||
277 | if __name__ == "__main__": | ||
278 | _test() | ||