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) |
