diff options
author | Paul Eggleton <paul.eggleton@linux.intel.com> | 2016-05-30 10:21:00 +1200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-06-01 12:38:41 +0100 |
commit | eb097357374521324ef569d84a4b56c5879eb8ec (patch) | |
tree | fb67ba9a3e5a6ac056847bd1727185bc1e3f6abf | |
parent | 2b510f5e018fed5f0e679d887656a501a6a38aaa (diff) | |
download | poky-eb097357374521324ef569d84a4b56c5879eb8ec.tar.gz |
recipetool: create: extract variable values from .deb/.ipk/.rpm
Extract the metadata from package files and use it to set variable
values in the recipe (including recipe name and version, LICENSE,
SUMMARY, DESCRIPTION, SECTION and HOMEPAGE). For LICENSE we take care
not to step on any value determined by our license file scan; if there
is one we simply add a comment above the LICENSE setting so the user can
resolve it.
(From OE-Core rev: 19e6b661d38c5ae9b19d6340762c289830baba59)
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r-- | scripts/lib/recipetool/create.py | 105 |
1 files changed, 94 insertions, 11 deletions
diff --git a/scripts/lib/recipetool/create.py b/scripts/lib/recipetool/create.py index 66c881a17a..ad2618963d 100644 --- a/scripts/lib/recipetool/create.py +++ b/scripts/lib/recipetool/create.py | |||
@@ -261,7 +261,11 @@ def determine_from_filename(srcfile): | |||
261 | namepart = srcfile.split('.tar.')[0].lower() | 261 | namepart = srcfile.split('.tar.')[0].lower() |
262 | else: | 262 | else: |
263 | namepart = os.path.splitext(srcfile)[0].lower() | 263 | namepart = os.path.splitext(srcfile)[0].lower() |
264 | splitval = namepart.rsplit('_', 1) | 264 | if is_package(srcfile): |
265 | # Force getting the value from the package metadata | ||
266 | return None, None | ||
267 | else: | ||
268 | splitval = namepart.rsplit('_', 1) | ||
265 | if len(splitval) == 1: | 269 | if len(splitval) == 1: |
266 | splitval = namepart.rsplit('-', 1) | 270 | splitval = namepart.rsplit('-', 1) |
267 | pn = splitval[0].replace('_', '-') | 271 | pn = splitval[0].replace('_', '-') |
@@ -327,6 +331,13 @@ def reformat_git_uri(uri): | |||
327 | return 'git://%s;protocol=%s%s' % (res.group(2), res.group(1), res.group(4) or '') | 331 | return 'git://%s;protocol=%s%s' % (res.group(2), res.group(1), res.group(4) or '') |
328 | return uri | 332 | return uri |
329 | 333 | ||
334 | def is_package(url): | ||
335 | '''Check if a URL points to a package''' | ||
336 | checkurl = url.split(';', 1)[0] | ||
337 | if checkurl.endswith(('.deb', '.ipk', '.rpm', '.srpm')): | ||
338 | return True | ||
339 | return False | ||
340 | |||
330 | def create_recipe(args): | 341 | def create_recipe(args): |
331 | import bb.process | 342 | import bb.process |
332 | import tempfile | 343 | import tempfile |
@@ -337,6 +348,7 @@ def create_recipe(args): | |||
337 | if args.machine: | 348 | if args.machine: |
338 | pkgarch = "${MACHINE_ARCH}" | 349 | pkgarch = "${MACHINE_ARCH}" |
339 | 350 | ||
351 | extravalues = {} | ||
340 | checksums = (None, None) | 352 | checksums = (None, None) |
341 | tempsrc = '' | 353 | tempsrc = '' |
342 | srcsubdir = '' | 354 | srcsubdir = '' |
@@ -382,6 +394,33 @@ def create_recipe(args): | |||
382 | if '<html' in f.read(100).lower(): | 394 | if '<html' in f.read(100).lower(): |
383 | logger.error('Fetching "%s" returned a single HTML page - check the URL is correct and functional' % fetchuri) | 395 | logger.error('Fetching "%s" returned a single HTML page - check the URL is correct and functional' % fetchuri) |
384 | sys.exit(1) | 396 | sys.exit(1) |
397 | |||
398 | if is_package(fetchuri): | ||
399 | tmpfdir = tempfile.mkdtemp(prefix='recipetool-') | ||
400 | try: | ||
401 | pkgfile = None | ||
402 | try: | ||
403 | fileuri = fetchuri + ';unpack=0' | ||
404 | scriptutils.fetch_uri(tinfoil.config_data, fileuri, tmpfdir, srcrev) | ||
405 | for root, _, files in os.walk(tmpfdir): | ||
406 | for f in files: | ||
407 | pkgfile = os.path.join(root, f) | ||
408 | break | ||
409 | except bb.fetch2.BBFetchException as e: | ||
410 | logger.warn('Second fetch to get metadata failed: %s' % str(e).rstrip()) | ||
411 | |||
412 | if pkgfile: | ||
413 | if pkgfile.endswith(('.deb', '.ipk')): | ||
414 | stdout, _ = bb.process.run('ar x %s control.tar.gz' % pkgfile, cwd=tmpfdir) | ||
415 | stdout, _ = bb.process.run('tar xf control.tar.gz ./control', cwd=tmpfdir) | ||
416 | values = convert_debian(tmpfdir) | ||
417 | extravalues.update(values) | ||
418 | elif pkgfile.endswith(('.rpm', '.srpm')): | ||
419 | stdout, _ = bb.process.run('rpm -qp --xml %s > pkginfo.xml' % pkgfile, cwd=tmpfdir) | ||
420 | values = convert_rpm_xml(os.path.join(tmpfdir, 'pkginfo.xml')) | ||
421 | extravalues.update(values) | ||
422 | finally: | ||
423 | shutil.rmtree(tmpfdir) | ||
385 | else: | 424 | else: |
386 | # Assume we're pointing to an existing source tree | 425 | # Assume we're pointing to an existing source tree |
387 | if args.extract_to: | 426 | if args.extract_to: |
@@ -458,6 +497,13 @@ def create_recipe(args): | |||
458 | lines_before.append('# will not be in most cases) you must specify the correct value before using this') | 497 | lines_before.append('# will not be in most cases) you must specify the correct value before using this') |
459 | lines_before.append('# recipe for anything other than initial testing/development!') | 498 | lines_before.append('# recipe for anything other than initial testing/development!') |
460 | licenses = ['CLOSED'] | 499 | licenses = ['CLOSED'] |
500 | pkg_license = extravalues.pop('LICENSE', None) | ||
501 | if pkg_license: | ||
502 | if licenses == ['Unknown']: | ||
503 | lines_before.append('# NOTE: The following LICENSE value was determined from the original package metadata') | ||
504 | licenses = [pkg_license] | ||
505 | else: | ||
506 | lines_before.append('# NOTE: Original package metadata indicates license is: %s' % pkg_license) | ||
461 | lines_before.append('LICENSE = "%s"' % ' '.join(licenses)) | 507 | lines_before.append('LICENSE = "%s"' % ' '.join(licenses)) |
462 | lines_before.append('LIC_FILES_CHKSUM = "%s"' % ' \\\n '.join(lic_files_chksum)) | 508 | lines_before.append('LIC_FILES_CHKSUM = "%s"' % ' \\\n '.join(lic_files_chksum)) |
463 | lines_before.append('') | 509 | lines_before.append('') |
@@ -558,7 +604,6 @@ def create_recipe(args): | |||
558 | classes.append('bin_package') | 604 | classes.append('bin_package') |
559 | handled.append('buildsystem') | 605 | handled.append('buildsystem') |
560 | 606 | ||
561 | extravalues = {} | ||
562 | for handler in handlers: | 607 | for handler in handlers: |
563 | handler.process(srctree_use, classes, lines_before, lines_after, handled, extravalues) | 608 | handler.process(srctree_use, classes, lines_before, lines_after, handled, extravalues) |
564 | 609 | ||
@@ -665,6 +710,9 @@ def create_recipe(args): | |||
665 | outlines.extend(lines_after) | 710 | outlines.extend(lines_after) |
666 | 711 | ||
667 | if extravalues: | 712 | if extravalues: |
713 | if 'LICENSE' in extravalues and not licvalues: | ||
714 | # Don't blow away 'CLOSED' value that comments say we set | ||
715 | del extravalues['LICENSE'] | ||
668 | _, outlines = oe.recipeutils.patch_recipe_lines(outlines, extravalues, trailing_newline=False) | 716 | _, outlines = oe.recipeutils.patch_recipe_lines(outlines, extravalues, trailing_newline=False) |
669 | 717 | ||
670 | if args.extract_to: | 718 | if args.extract_to: |
@@ -913,6 +961,12 @@ def convert_pkginfo(pkginfofile): | |||
913 | return values | 961 | return values |
914 | 962 | ||
915 | def convert_debian(debpath): | 963 | def convert_debian(debpath): |
964 | value_map = {'Package': 'PN', | ||
965 | 'Version': 'PV', | ||
966 | 'Section': 'SECTION', | ||
967 | 'License': 'LICENSE', | ||
968 | 'Homepage': 'HOMEPAGE'} | ||
969 | |||
916 | # FIXME extend this mapping - perhaps use distro_alias.inc? | 970 | # FIXME extend this mapping - perhaps use distro_alias.inc? |
917 | depmap = {'libz-dev': 'zlib'} | 971 | depmap = {'libz-dev': 'zlib'} |
918 | 972 | ||
@@ -922,34 +976,63 @@ def convert_debian(debpath): | |||
922 | indesc = False | 976 | indesc = False |
923 | for line in f: | 977 | for line in f: |
924 | if indesc: | 978 | if indesc: |
925 | if line.strip(): | 979 | if line.startswith(' '): |
926 | if line.startswith(' This package contains'): | 980 | if line.startswith(' This package contains'): |
927 | indesc = False | 981 | indesc = False |
928 | else: | 982 | else: |
929 | values['DESCRIPTION'] += ' ' + line.strip() | 983 | if 'DESCRIPTION' in values: |
984 | values['DESCRIPTION'] += ' ' + line.strip() | ||
985 | else: | ||
986 | values['DESCRIPTION'] = line.strip() | ||
930 | else: | 987 | else: |
931 | indesc = False | 988 | indesc = False |
932 | else: | 989 | if not indesc: |
933 | splitline = line.split(':', 1) | 990 | splitline = line.split(':', 1) |
934 | key = line[0] | 991 | if len(splitline) < 2: |
935 | value = line[1] | 992 | continue |
993 | key = splitline[0] | ||
994 | value = splitline[1].strip() | ||
936 | if key == 'Build-Depends': | 995 | if key == 'Build-Depends': |
937 | for dep in value.split(','): | 996 | for dep in value.split(','): |
938 | dep = dep.split()[0] | 997 | dep = dep.split()[0] |
939 | mapped = depmap.get(dep, '') | 998 | mapped = depmap.get(dep, '') |
940 | if mapped: | 999 | if mapped: |
941 | depends.append(mapped) | 1000 | depends.append(mapped) |
942 | elif key == 'Section': | ||
943 | values['SECTION'] = value | ||
944 | elif key == 'Description': | 1001 | elif key == 'Description': |
945 | values['SUMMARY'] = value | 1002 | values['SUMMARY'] = value |
946 | indesc = True | 1003 | indesc = True |
1004 | else: | ||
1005 | varname = value_map.get(key, None) | ||
1006 | if varname: | ||
1007 | values[varname] = value | ||
947 | 1008 | ||
948 | if depends: | 1009 | #if depends: |
949 | values['DEPENDS'] = ' '.join(depends) | 1010 | # values['DEPENDS'] = ' '.join(depends) |
950 | 1011 | ||
951 | return values | 1012 | return values |
952 | 1013 | ||
1014 | def convert_rpm_xml(xmlfile): | ||
1015 | '''Converts the output from rpm -qp --xml to a set of variable values''' | ||
1016 | import xml.etree.ElementTree as ElementTree | ||
1017 | rpmtag_map = {'Name': 'PN', | ||
1018 | 'Version': 'PV', | ||
1019 | 'Summary': 'SUMMARY', | ||
1020 | 'Description': 'DESCRIPTION', | ||
1021 | 'License': 'LICENSE', | ||
1022 | 'Url': 'HOMEPAGE'} | ||
1023 | |||
1024 | values = {} | ||
1025 | tree = ElementTree.parse(xmlfile) | ||
1026 | root = tree.getroot() | ||
1027 | for child in root: | ||
1028 | if child.tag == 'rpmTag': | ||
1029 | name = child.attrib.get('name', None) | ||
1030 | if name: | ||
1031 | varname = rpmtag_map.get(name, None) | ||
1032 | if varname: | ||
1033 | values[varname] = child[0].text | ||
1034 | return values | ||
1035 | |||
953 | 1036 | ||
954 | def register_commands(subparsers): | 1037 | def register_commands(subparsers): |
955 | parser_create = subparsers.add_parser('create', | 1038 | parser_create = subparsers.add_parser('create', |