diff options
author | Paul Eggleton <paul.eggleton@linux.intel.com> | 2015-12-22 17:03:02 +1300 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2015-12-28 09:25:13 +0000 |
commit | db5f9645ad3ffb4e9be7075d71cb1b13341f5195 (patch) | |
tree | 3c4bfcfc698840c310d069f26b57863fde877528 /scripts/lib/recipetool/create.py | |
parent | 6a7661b8005fadad10bde494131e27406e1e45b8 (diff) | |
download | poky-db5f9645ad3ffb4e9be7075d71cb1b13341f5195.tar.gz |
recipetool: create: support extracting name and version from build scripts
Some build systems (notably autotools) support declaring the name and
version of the program being built; since we need those for the recipe
we can attempt to extract them. It's a little fuzzy as they are often
omitted or may not be appropriately formatted for our purposes, but it
does work on a reasonable number of software packages to be useful.
(From OE-Core rev: 3b3fd33190d89c09e62126eea0e45aa84fe5442e)
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts/lib/recipetool/create.py')
-rw-r--r-- | scripts/lib/recipetool/create.py | 130 |
1 files changed, 104 insertions, 26 deletions
diff --git a/scripts/lib/recipetool/create.py b/scripts/lib/recipetool/create.py index 5c249ab0c6..6c7b9fd7e8 100644 --- a/scripts/lib/recipetool/create.py +++ b/scripts/lib/recipetool/create.py | |||
@@ -41,10 +41,17 @@ def tinfoil_init(instance): | |||
41 | 41 | ||
42 | class RecipeHandler(): | 42 | class RecipeHandler(): |
43 | @staticmethod | 43 | @staticmethod |
44 | def checkfiles(path, speclist): | 44 | def checkfiles(path, speclist, recursive=False): |
45 | results = [] | 45 | results = [] |
46 | for spec in speclist: | 46 | if recursive: |
47 | results.extend(glob.glob(os.path.join(path, spec))) | 47 | for root, _, files in os.walk(path): |
48 | for fn in files: | ||
49 | for spec in speclist: | ||
50 | if fnmatch.fnmatch(fn, spec): | ||
51 | results.append(os.path.join(root, fn)) | ||
52 | else: | ||
53 | for spec in speclist: | ||
54 | results.extend(glob.glob(os.path.join(path, spec))) | ||
48 | return results | 55 | return results |
49 | 56 | ||
50 | def genfunction(self, outlines, funcname, content, python=False, forcespace=False): | 57 | def genfunction(self, outlines, funcname, content, python=False, forcespace=False): |
@@ -70,10 +77,14 @@ class RecipeHandler(): | |||
70 | outlines.append('}') | 77 | outlines.append('}') |
71 | outlines.append('') | 78 | outlines.append('') |
72 | 79 | ||
73 | def process(self, srctree, classes, lines_before, lines_after, handled): | 80 | def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): |
74 | return False | 81 | return False |
75 | 82 | ||
76 | 83 | ||
84 | def validate_pv(pv): | ||
85 | if not pv or '_version' in pv.lower() or pv[0] not in '0123456789': | ||
86 | return False | ||
87 | return True | ||
77 | 88 | ||
78 | def supports_srcrev(uri): | 89 | def supports_srcrev(uri): |
79 | localdata = bb.data.createCopy(tinfoil.config_data) | 90 | localdata = bb.data.createCopy(tinfoil.config_data) |
@@ -152,7 +163,12 @@ def create_recipe(args): | |||
152 | srcuri = '' | 163 | srcuri = '' |
153 | srctree = args.source | 164 | srctree = args.source |
154 | 165 | ||
155 | outfile = args.outfile | 166 | if args.outfile and os.path.isdir(args.outfile): |
167 | outfile = None | ||
168 | outdir = args.outfile | ||
169 | else: | ||
170 | outfile = args.outfile | ||
171 | outdir = None | ||
156 | if outfile and outfile != '-': | 172 | if outfile and outfile != '-': |
157 | if os.path.exists(outfile): | 173 | if os.path.exists(outfile): |
158 | logger.error('Output file %s already exists' % outfile) | 174 | logger.error('Output file %s already exists' % outfile) |
@@ -196,28 +212,29 @@ def create_recipe(args): | |||
196 | lines_before.append('') | 212 | lines_before.append('') |
197 | 213 | ||
198 | # FIXME This is kind of a hack, we probably ought to be using bitbake to do this | 214 | # FIXME This is kind of a hack, we probably ought to be using bitbake to do this |
199 | # we'd also want a way to automatically set outfile based upon auto-detecting these values from the source if possible | 215 | pn = None |
200 | recipefn = os.path.splitext(os.path.basename(outfile))[0] | 216 | pv = None |
201 | fnsplit = recipefn.split('_') | 217 | if outfile: |
202 | if len(fnsplit) > 1: | 218 | recipefn = os.path.splitext(os.path.basename(outfile))[0] |
203 | pn = fnsplit[0] | 219 | fnsplit = recipefn.split('_') |
204 | pv = fnsplit[1] | 220 | if len(fnsplit) > 1: |
205 | else: | 221 | pn = fnsplit[0] |
206 | pn = recipefn | 222 | pv = fnsplit[1] |
207 | pv = None | 223 | else: |
224 | pn = recipefn | ||
208 | 225 | ||
209 | if args.version: | 226 | if args.version: |
210 | pv = args.version | 227 | pv = args.version |
211 | 228 | ||
229 | if args.name: | ||
230 | pn = args.name | ||
231 | |||
212 | if pv and pv not in 'git svn hg'.split(): | 232 | if pv and pv not in 'git svn hg'.split(): |
213 | realpv = pv | 233 | realpv = pv |
214 | else: | 234 | else: |
215 | realpv = None | 235 | realpv = None |
216 | 236 | ||
217 | if srcuri: | 237 | if not srcuri: |
218 | if realpv: | ||
219 | srcuri = srcuri.replace(realpv, '${PV}') | ||
220 | else: | ||
221 | lines_before.append('# No information for SRC_URI yet (only an external source tree was specified)') | 238 | lines_before.append('# No information for SRC_URI yet (only an external source tree was specified)') |
222 | lines_before.append('SRC_URI = "%s"' % srcuri) | 239 | lines_before.append('SRC_URI = "%s"' % srcuri) |
223 | (md5value, sha256value) = checksums | 240 | (md5value, sha256value) = checksums |
@@ -232,13 +249,7 @@ def create_recipe(args): | |||
232 | lines_before.append('SRCREV = "%s"' % srcrev) | 249 | lines_before.append('SRCREV = "%s"' % srcrev) |
233 | lines_before.append('') | 250 | lines_before.append('') |
234 | 251 | ||
235 | if srcsubdir and pv: | ||
236 | if srcsubdir == "%s-%s" % (pn, pv): | ||
237 | # This would be the default, so we don't need to set S in the recipe | ||
238 | srcsubdir = '' | ||
239 | if srcsubdir: | 252 | if srcsubdir: |
240 | if pv and pv not in 'git svn hg'.split(): | ||
241 | srcsubdir = srcsubdir.replace(pv, '${PV}') | ||
242 | lines_before.append('S = "${WORKDIR}/%s"' % srcsubdir) | 253 | lines_before.append('S = "${WORKDIR}/%s"' % srcsubdir) |
243 | lines_before.append('') | 254 | lines_before.append('') |
244 | 255 | ||
@@ -276,8 +287,74 @@ def create_recipe(args): | |||
276 | classes.append('bin_package') | 287 | classes.append('bin_package') |
277 | handled.append('buildsystem') | 288 | handled.append('buildsystem') |
278 | 289 | ||
290 | extravalues = {} | ||
279 | for handler in handlers: | 291 | for handler in handlers: |
280 | handler.process(srctree, classes, lines_before, lines_after, handled) | 292 | handler.process(srctree, classes, lines_before, lines_after, handled, extravalues) |
293 | |||
294 | if not realpv: | ||
295 | realpv = extravalues.get('PV', None) | ||
296 | if realpv: | ||
297 | if not validate_pv(realpv): | ||
298 | realpv = None | ||
299 | else: | ||
300 | realpv = realpv.lower().split()[0] | ||
301 | if '_' in realpv: | ||
302 | realpv = realpv.replace('_', '-') | ||
303 | if not pn: | ||
304 | pn = extravalues.get('PN', None) | ||
305 | if pn: | ||
306 | if pn.startswith('GNU '): | ||
307 | pn = pn[4:] | ||
308 | if ' ' in pn: | ||
309 | # Probably a descriptive identifier rather than a proper name | ||
310 | pn = None | ||
311 | else: | ||
312 | pn = pn.lower() | ||
313 | if '_' in pn: | ||
314 | pn = pn.replace('_', '-') | ||
315 | |||
316 | if not outfile: | ||
317 | if not pn: | ||
318 | logger.error('Unable to determine short program name from source tree - please specify name with -N/--name or output file name with -o/--outfile') | ||
319 | # devtool looks for this specific exit code, so don't change it | ||
320 | sys.exit(15) | ||
321 | else: | ||
322 | if srcuri and srcuri.startswith(('git://', 'hg://', 'svn://')): | ||
323 | outfile = '%s_%s.bb' % (pn, srcuri.split(':', 1)[0]) | ||
324 | elif realpv: | ||
325 | outfile = '%s_%s.bb' % (pn, realpv) | ||
326 | else: | ||
327 | outfile = '%s.bb' % pn | ||
328 | if outdir: | ||
329 | outfile = os.path.join(outdir, outfile) | ||
330 | # We need to check this again | ||
331 | if os.path.exists(outfile): | ||
332 | logger.error('Output file %s already exists' % outfile) | ||
333 | sys.exit(1) | ||
334 | |||
335 | lines = lines_before | ||
336 | lines_before = [] | ||
337 | skipblank = True | ||
338 | for line in lines: | ||
339 | if skipblank: | ||
340 | skipblank = False | ||
341 | if not line: | ||
342 | continue | ||
343 | if line.startswith('S = '): | ||
344 | if realpv and pv not in 'git svn hg'.split(): | ||
345 | line = line.replace(realpv, '${PV}') | ||
346 | if pn: | ||
347 | line = line.replace(pn, '${BPN}') | ||
348 | if line == 'S = "${WORKDIR}/${BPN}-${PV}"': | ||
349 | skipblank = True | ||
350 | continue | ||
351 | elif line.startswith('SRC_URI = '): | ||
352 | if realpv: | ||
353 | line = line.replace(realpv, '${PV}') | ||
354 | elif line.startswith('PV = '): | ||
355 | if realpv: | ||
356 | line = re.sub('"[^+]*\+', '"%s+' % realpv, line) | ||
357 | lines_before.append(line) | ||
281 | 358 | ||
282 | outlines = [] | 359 | outlines = [] |
283 | outlines.extend(lines_before) | 360 | outlines.extend(lines_before) |
@@ -469,9 +546,10 @@ def register_commands(subparsers): | |||
469 | help='Create a new recipe', | 546 | help='Create a new recipe', |
470 | description='Creates a new recipe from a source tree') | 547 | description='Creates a new recipe from a source tree') |
471 | parser_create.add_argument('source', help='Path or URL to source') | 548 | parser_create.add_argument('source', help='Path or URL to source') |
472 | parser_create.add_argument('-o', '--outfile', help='Specify filename for recipe to create', required=True) | 549 | parser_create.add_argument('-o', '--outfile', help='Specify filename for recipe to create') |
473 | parser_create.add_argument('-m', '--machine', help='Make recipe machine-specific as opposed to architecture-specific', action='store_true') | 550 | parser_create.add_argument('-m', '--machine', help='Make recipe machine-specific as opposed to architecture-specific', action='store_true') |
474 | parser_create.add_argument('-x', '--extract-to', metavar='EXTRACTPATH', help='Assuming source is a URL, fetch it and extract it to the directory specified as %(metavar)s') | 551 | parser_create.add_argument('-x', '--extract-to', metavar='EXTRACTPATH', help='Assuming source is a URL, fetch it and extract it to the directory specified as %(metavar)s') |
552 | parser_create.add_argument('-N', '--name', help='Name to use within recipe (PN)') | ||
475 | parser_create.add_argument('-V', '--version', help='Version to use within recipe (PV)') | 553 | parser_create.add_argument('-V', '--version', help='Version to use within recipe (PV)') |
476 | parser_create.add_argument('-b', '--binary', help='Treat the source tree as something that should be installed verbatim (no compilation, same directory structure)', action='store_true') | 554 | parser_create.add_argument('-b', '--binary', help='Treat the source tree as something that should be installed verbatim (no compilation, same directory structure)', action='store_true') |
477 | parser_create.set_defaults(func=create_recipe) | 555 | parser_create.set_defaults(func=create_recipe) |