devtool/recipetool fixes rollup
cover devtool/recipetool fixes rollup
This patchset rolls up a few of the pending patches with minimal changes and introduces a couple of mine.
Leo's import/export patches have had the file change function patch squashed into the import patch, and I also made it use DevtoolError instead of logger.error()+sys.exit() in a couple of places, used with... to ensure the tarfile got closed in the import module and tweaked the commit messages.
In Rebecca's devtool upgrade patch I removed an unnecessary sys.exit() after raise DevtoolError(...).
These patches have passed oe-selftest devtool/recipetool tests locally.
The following changes since commit 5c9ef0734d23909b5694ed43cdbb205c2ba9ca95:
devtool/copy_buildsystem: adds meta-skeleton layer in the eSDK installation. (2017-08-19 22:15:25 +0100)
are available in the git repository at:
git://git.openembedded.org/openembedded-core-contrib paule/devtool28-oe
http://cgit.openembedded.org/openembedded-core-contrib/log/?h=paule/devtool28-oe
Chang Rebecca Swee Fun (3):
recipetool: create: disable PREMIRRORS and MIRRORS by default
recipetool: create: being able to set branch when revision is provided
devtool: upgrade: enable branch checking when revision is provided
Leonardo Sandoval (3):
devtool: export: new plugin to export the devtool workspace
devtool: append md5sum only if not already present
devtool: import: new plugin to import the devtool workspace
Paul Eggleton (2):
recipetool: allow plugins to set PN / PV more easily
recipetool: allow plugins to set LICENSE and LIC_FILES_CHKSUM
Stanley Phoong (2):
recipetool: create: handle git URLs specifying only a tag
recipetool: create: replacing PV in SRCURI
scripts/lib/devtool/__init__.py | 36 ++++++ scripts/lib/devtool/export.py | 119 ++++++++++++++++++++ scripts/lib/devtool/import.py | 144 ++++++++++++++++++++++++ scripts/lib/devtool/standard.py | 7 +- scripts/lib/devtool/upgrade.py | 27 ++++- scripts/lib/recipetool/create.py | 205 +++++++++++++++++++++++++++-------- scripts/lib/recipetool/create_npm.py | 44 +------- scripts/lib/scriptutils.py | 9 +- 8 files changed, 495 insertions(+), 96 deletions(-) create mode 100644 scripts/lib/devtool/export.py create mode 100644 scripts/lib/devtool/import.py
Signature · 1 line
2.9.5
PATCH 1/10 recipetool: create: disable PREMIRRORS and MIRRORS by default
From: Chang Rebecca Swee Fun <[email protected]>
When creating new recipes, we are almost certainly fetching a new source rather that something that has already been fetched. I have disable PREMIRRORS and MIRRORS settings in the recipe that created by devtool while leaving an option for users to enable them manually if needed. Since devtool already has this options, we need to ensure that recipetool is able to handle the options passed from devtool.
--- scripts/lib/recipetool/create.py | 1 + scripts/lib/scriptutils.py | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-)
scripts/lib/recipetool/create.py +1 -0
@@ -1169,5 +1169,6 @@ def register_commands(subparsers): parser_create.add_argument('--keep-temp', action="store_true", help='Keep temporary directory (for debugging)') parser_create.add_argument('--fetch-dev', action="store_true", help='For npm, also fetch devDependencies') parser_create.add_argument('--devtool', action="store_true", help=argparse.SUPPRESS) + parser_create.add_argument('--mirrors', action="store_true", help='Enable PREMIRRORS and MIRRORS for source tree fetching (disabled by default).') parser_create.set_defaults(func=create_recipe)
scripts/lib/scriptutils.py +8 -1
@@ -102,7 +102,7 @@ class FetchUrlFailure(Exception): def __str__(self): return "Failed to fetch URL %s" % self.url -def fetch_url(tinfoil, srcuri, srcrev, destdir, logger, preserve_tmp=False): +def fetch_url(tinfoil, srcuri, srcrev, destdir, logger, preserve_tmp=False, mirrors=False): """ Fetch the specified URL using normal do_fetch and do_unpack tasks, i.e. any dependencies that need to be satisfied in order to support the fetch
@@ -150,6 +150,13 @@ def fetch_url(tinfoil, srcuri, srcrev, destdir, logger, preserve_tmp=False): f.write('WORKDIR = "%s"\n' % tmpworkdir) # Set S out of the way so it doesn't get created under the workdir f.write('S = "%s"\n' % os.path.join(tmpdir, 'emptysrc')) + if not mirrors: + # We do not need PREMIRRORS since we are almost certainly + # fetching new source rather than something that has already + # been fetched. Hence, we disable them by default. + # However, we provide an option for users to enable it. + f.write('PREMIRRORS = ""\n') + f.write('MIRRORS = ""\n') logger.info('Fetching %s...' % srcuri)
Signature · 1 line
2.9.5
PATCH 2/10 recipetool: create: being able to set branch when revision is provided
In reply to Paul EggletonFrom: Chang Rebecca Swee Fun <[email protected]>
This change is to improve the buildability of the recipe created by recipetool and devtool.
When recipetool create is run on a git URL and a revision specified that is not on master, and "branch=" isn't already in the URL, then we should get the correct branch and append the branch to the URL.
If the revision was found on multiple branches and 'master' is not in the list, we will display error to inform user to provide a correct branch and exit.
[YOCTO #11389]
--- scripts/lib/recipetool/create.py | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+)
scripts/lib/recipetool/create.py +48 -0
@@ -422,6 +422,7 @@ def create_recipe(args): source = args.source srcsubdir = '' srcrev = '${AUTOREV}' + srcbranch = '' if os.path.isfile(source): source = 'file://%s' % os.path.abspath(source)
@@ -440,6 +441,19 @@ def create_recipe(args): srcrev = res.group(1) srcuri = rev_re.sub('', srcuri) + # Check whether users provides any branch info in fetchuri. + # If true, we will skip all branch checking process to honor all user's input. + scheme, network, path, user, passwd, params = bb.fetch2.decodeurl(fetchuri) + srcbranch = params.get('branch') + nobranch = params.get('nobranch') + if not srcbranch and not nobranch and srcrev != '${AUTOREV}': + # Append nobranch=1 in the following conditions: + # 1. User did not set 'branch=' in srcuri, and + # 2. User did not set 'nobranch=1' in srcuri, and + # 3. Source revision is not '${AUTOREV}' + params['nobranch'] = '1' + fetchuri = bb.fetch2.encodeurl((scheme, network, path, user, passwd, params)) + tmpparent = tinfoil.config_data.getVar('BASE_WORKDIR') bb.utils.mkdirhier(tmpparent) tempsrc = tempfile.mkdtemp(prefix='recipetool-', dir=tmpparent)
@@ -475,6 +489,40 @@ def create_recipe(args): logger.error('URL %s resulted in an empty source tree' % fetchuri) sys.exit(1) + # We need this checking mechanism to improve the recipe created by recipetool and devtool + # is able to parse and build by bitbake. + # If there is no input for branch name, then check for branch name with SRCREV provided. + if not srcbranch and not nobranch and srcrev and (srcrev != '${AUTOREV}'): + try: + cmd = 'git branch -r --contains' + check_branch, check_branch_err = bb.process.run('%s %s' % (cmd, srcrev), cwd=srctree) + except bb.process.ExecutionError as err: + logger.error(str(err)) + sys.exit(1) + get_branch = [x.strip() for x in check_branch.splitlines()] + # Remove HEAD reference point and drop remote prefix + get_branch = [x.split('/', 1)[1] for x in get_branch if not x.startswith('origin/HEAD')] + if 'master' in get_branch: + # If it is master, we do not need to append 'branch=master' as this is default. + # Even with the case where get_branch has multiple objects, if 'master' is one + # of them, we should default take from 'master' + srcbranch = '' + elif len(get_branch) == 1: + # If 'master' isn't in get_branch and get_branch contains only ONE object, then store result into 'srcbranch' + srcbranch = get_branch[0] + else: + # If get_branch contains more than one objects, then display error and exit. + mbrch = '\n ' + '\n '.join(get_branch) + logger.error('Revision %s was found on multiple branches: %s\nPlease provide the correct branch in the source URL with ;branch=<branch> (and ensure you use quotes around the URL to avoid the shell interpreting the ";")' % (srcrev, mbrch)) + sys.exit(1) + + # Since we might have a value in srcbranch, we need to + # recontruct the srcuri to include 'branch' in params. + if srcbranch: + scheme, network, path, user, passwd, params = bb.fetch2.decodeurl(srcuri) + params['branch'] = srcbranch + srcuri = bb.fetch2.encodeurl((scheme, network, path, user, passwd, params)) + if os.path.exists(os.path.join(srctree, '.gitmodules')) and srcuri.startswith('git://'): srcuri = 'gitsm://' + srcuri[6:] logger.info('Fetching submodules...')
Signature · 1 line
2.9.5
PATCH 3/10 recipetool: create: handle git URLs specifying only a tag
In reply to Paul EggletonFrom: Stanley Phoong <[email protected]>
If a git URL is passed to recipetool create with a tag=, recipetool should handle it assuming that the tag is valid.
[YOCTO #11393]
--- scripts/lib/recipetool/create.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
scripts/lib/recipetool/create.py +22 -1
@@ -423,6 +423,7 @@ def create_recipe(args): srcsubdir = '' srcrev = '${AUTOREV}' srcbranch = '' + storeTagName = '' if os.path.isfile(source): source = 'file://%s' % os.path.abspath(source)
@@ -446,13 +447,21 @@ def create_recipe(args): scheme, network, path, user, passwd, params = bb.fetch2.decodeurl(fetchuri) srcbranch = params.get('branch') nobranch = params.get('nobranch') + tag = params.get('tag') if not srcbranch and not nobranch and srcrev != '${AUTOREV}': # Append nobranch=1 in the following conditions: # 1. User did not set 'branch=' in srcuri, and # 2. User did not set 'nobranch=1' in srcuri, and # 3. Source revision is not '${AUTOREV}' params['nobranch'] = '1' - fetchuri = bb.fetch2.encodeurl((scheme, network, path, user, passwd, params)) + if tag: + # Keep a copy of tag and append nobranch=1 then remove tag from URL. + # Bitbake fetcher unable to fetch when {AUTOREV} and tag is set at the same time. + # We will re-introduce tag argument after bitbake fetcher process is complete. + storeTagName = params['tag'] + params['nobranch'] = '1' + del params['tag'] + fetchuri = bb.fetch2.encodeurl((scheme, network, path, user, passwd, params)) tmpparent = tinfoil.config_data.getVar('BASE_WORKDIR') bb.utils.mkdirhier(tmpparent)
@@ -523,6 +532,18 @@ def create_recipe(args): params['branch'] = srcbranch srcuri = bb.fetch2.encodeurl((scheme, network, path, user, passwd, params)) + if storeTagName: + # Re-introduced tag variable from storeTagName + # Check srcrev using tag and check validity of the tag + cmd = ('git rev-parse --verify %s' % (storeTagName)) + try: + check_tag, check_tag_err = bb.process.run('%s' % cmd, cwd=srctree) + srcrev = check_tag.split()[0] + except bb.process.ExecutionError as err: + logger.error(str(err)) + logger.error("Possibly wrong tag name is provided") + sys.exit(1) + if os.path.exists(os.path.join(srctree, '.gitmodules')) and srcuri.startswith('git://'): srcuri = 'gitsm://' + srcuri[6:] logger.info('Fetching submodules...')
Signature · 1 line
2.9.5
PATCH 4/10 recipetool: create: replacing PV in SRCURI
In reply to Paul EggletonFrom: Stanley Phoong <[email protected]>
During recipe creation, it seems that the automation for replacing ${PV} at the SRCURI for tag, (e.g mbed-tls-${PV}) is causing some issue due to PV assuming it's a git source. A fix is implemented in this patch to resolve this issue.
--- scripts/lib/recipetool/create.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
scripts/lib/recipetool/create.py +3 -1
@@ -424,6 +424,7 @@ def create_recipe(args): srcrev = '${AUTOREV}' srcbranch = '' storeTagName = '' + pv_srcpv = False if os.path.isfile(source): source = 'file://%s' % os.path.abspath(source)
@@ -671,6 +672,7 @@ def create_recipe(args): lines_before.append('') lines_before.append('# Modify these as desired') lines_before.append('PV = "%s+git${SRCPV}"' % (realpv or '1.0')) + pv_srcpv = True if not args.autorev and srcrev == '${AUTOREV}': if os.path.exists(os.path.join(srctree, '.git')): (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srctree)
@@ -797,7 +799,7 @@ def create_recipe(args): skipblank = True continue elif line.startswith('SRC_URI = '): - if realpv: + if realpv and not pv_srcpv: line = line.replace(realpv, '${PV}') elif line.startswith('PV = '): if realpv:
Signature · 1 line
2.9.5
PATCH 5/10 devtool: upgrade: enable branch checking when revision is provided
In reply to Paul EggletonFrom: Chang Rebecca Swee Fun <[email protected]>
When devtool upgrade is run on a recipe with revision specified that is not on master branch, and branch isn't set by --srcbranch or -B, then we should get the correct branch and append the branch to the URL.
If the revision was found on multiple branches, we will display error to inform user to provide a correct branch and exit.
[YOCTO #11484]
--- scripts/lib/devtool/upgrade.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-)
scripts/lib/devtool/upgrade.py +22 -5
@@ -180,7 +180,7 @@ def _get_uri(rd): srcuri = rev_re.sub('', srcuri) return srcuri, srcrev -def _extract_new_source(newpv, srctree, no_patch, srcrev, branch, keep_temp, tinfoil, rd): +def _extract_new_source(newpv, srctree, no_patch, srcrev, srcbranch, branch, keep_temp, tinfoil, rd): """Extract sources of a recipe with a new version""" def __run(cmd):
@@ -202,6 +202,23 @@ def _extract_new_source(newpv, srctree, no_patch, srcrev, branch, keep_temp, tin __run('git tag -f devtool-base-new') md5 = None sha256 = None + if not srcbranch: + check_branch, check_branch_err = __run('git branch -r --contains %s' % srcrev) + get_branch = [x.strip() for x in check_branch.splitlines()] + # Remove HEAD reference point and drop remote prefix + get_branch = [x.split('/', 1)[1] for x in get_branch if not x.startswith('origin/HEAD')] + if 'master' in get_branch: + # If it is master, we do not need to append 'branch=master' as this is default. + # Even with the case where get_branch has multiple objects, if 'master' is one + # of them, we should default take from 'master' + srcbranch = '' + elif len(get_branch) == 1: + # If 'master' isn't in get_branch and get_branch contains only ONE object, then store result into 'srcbranch' + srcbranch = get_branch[0] + else: + # If get_branch contains more than one objects, then display error and exit. + mbrch = '\n ' + '\n '.join(get_branch) + raise DevtoolError('Revision %s was found on multiple branches: %s\nPlease provide the correct branch in the devtool command with "--srcbranch" or "-B" option.' % (srcrev, mbrch)) else: __run('git checkout devtool-base -b devtool-%s' % newpv)
@@ -275,7 +292,7 @@ def _extract_new_source(newpv, srctree, no_patch, srcrev, branch, keep_temp, tin else: shutil.rmtree(tmpsrctree) - return (rev, md5, sha256) + return (rev, md5, sha256, srcbranch) def _create_new_recipe(newpv, md5, sha256, srcrev, srcbranch, workspace, tinfoil, rd): """Creates the new recipe under workspace"""
@@ -374,10 +391,10 @@ def upgrade(args, config, basepath, workspace): rf = None try: rev1 = standard._extract_source(srctree, False, 'devtool-orig', False, rd, tinfoil) - rev2, md5, sha256 = _extract_new_source(args.version, srctree, args.no_patch, - args.srcrev, args.branch, args.keep_temp, + rev2, md5, sha256, srcbranch = _extract_new_source(args.version, srctree, args.no_patch, + args.srcrev, args.srcbranch, args.branch, args.keep_temp, tinfoil, rd) - rf, copied = _create_new_recipe(args.version, md5, sha256, args.srcrev, args.srcbranch, config.workspace_path, tinfoil, rd) + rf, copied = _create_new_recipe(args.version, md5, sha256, args.srcrev, srcbranch, config.workspace_path, tinfoil, rd) except bb.process.CmdError as e: _upgrade_error(e, rf, srctree) except DevtoolError as e:
Signature · 1 line
2.9.5
PATCH 6/10 devtool: export: new plugin to export the devtool workspace
In reply to Paul EggletonFrom: Leonardo Sandoval <[email protected]>
By default, exports the whole workspace (all recipes) including the source code. User can also limit what is exported with --included/--excluded flags. As a result of this operation, a tar archive containing only workspace metadata and its corresponding source code is created, which can be properly imported with 'devtool import'.
https://bugzilla.yoctoproject.org/show_bug.cgi?id=10510
[YOCTO #10510]
--- scripts/lib/devtool/export.py | 119 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 scripts/lib/devtool/export.py
scripts/lib/devtool/export.py new file +119 -0
@@ -0,0 +1,119 @@ +# Development tool - export command plugin +# +# Copyright (C) 2014-2017 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +"""Devtool export plugin""" + +import os +import argparse +import tarfile +import logging +import datetime +import json + +logger = logging.getLogger('devtool') + +# output files +default_arcname_prefix = "workspace-export" +metadata = '.export_metadata' + +def export(args, config, basepath, workspace): + """Entry point for the devtool 'export' subcommand""" + + def add_metadata(tar): + """Archive the workspace object""" + # finally store the workspace metadata + with open(metadata, 'w') as fd: + fd.write(json.dumps((config.workspace_path, workspace))) + tar.add(metadata) + os.unlink(metadata) + + def add_recipe(tar, recipe, data): + """Archive recipe with proper arcname""" + # Create a map of name/arcnames + arcnames = [] + for key, name in data.items(): + if name: + if key == 'srctree': + # all sources, no matter where are located, goes into the sources directory + arcname = 'sources/%s' % recipe + else: + arcname = name.replace(config.workspace_path, '') + arcnames.append((name, arcname)) + + for name, arcname in arcnames: + tar.add(name, arcname=arcname) + + + # Make sure workspace is non-empty and possible listed include/excluded recipes are in workspace + if not workspace: + logger.info('Workspace contains no recipes, nothing to export') + return 0 + else: + for param, recipes in {'include':args.include,'exclude':args.exclude}.items(): + for recipe in recipes: + if recipe not in workspace: + logger.error('Recipe (%s) on %s argument not in the current workspace' % (recipe, param)) + return 1 + + name = args.file + + default_name = "%s-%s.tar.gz" % (default_arcname_prefix, datetime.datetime.now().strftime('%Y%m%d%H%M%S')) + if not name: + name = default_name + else: + # if name is a directory, append the default name + if os.path.isdir(name): + name = os.path.join(name, default_name) + + if os.path.exists(name) and not args.overwrite: + logger.error('Tar archive %s exists. Use --overwrite/-o to overwrite it') + return 1 + + # if all workspace is excluded, quit + if not len(set(workspace.keys()).difference(set(args.exclude))): + logger.warn('All recipes in workspace excluded, nothing to export') + return 0 + + exported = [] + with tarfile.open(name, 'w:gz') as tar: + if args.include: + for recipe in args.include: + add_recipe(tar, recipe, workspace[recipe]) + exported.append(recipe) + else: + for recipe, data in workspace.items(): + if recipe not in args.exclude: + add_recipe(tar, recipe, data) + exported.append(recipe) + + add_metadata(tar) + + logger.info('Tar archive created at %s with the following recipes: %s' % (name, ', '.join(exported))) + return 0 + +def register_commands(subparsers, context): + """Register devtool export subcommands""" + parser = subparsers.add_parser('export', + help='Export workspace into a tar archive', + description='Export one or more recipes from current workspace into a tar archive', + group='advanced') + + parser.add_argument('--file', '-f', help='Output archive file name') + parser.add_argument('--overwrite', '-o', action="store_true", help='Overwrite previous export tar archive') + group = parser.add_mutually_exclusive_group() + group.add_argument('--include', '-i', nargs='+', default=[], help='Include recipes into the tar archive') + group.add_argument('--exclude', '-e', nargs='+', default=[], help='Exclude recipes into the tar archive') + parser.set_defaults(func=export)
Signature · 1 line
2.9.5
PATCH 7/10 devtool: append md5sum only if not already present
In reply to Paul EggletonFrom: Leonardo Sandoval <[email protected]>
In case the proposed md5sum to be appended to the .devtool_md5 file is already present, do not append it.
--- scripts/lib/devtool/standard.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
scripts/lib/devtool/standard.py +5 -2
@@ -674,8 +674,11 @@ def _add_md5(config, recipename, filename): def addfile(fn): md5 = bb.utils.md5_file(fn) - with open(os.path.join(config.workspace_path, '.devtool_md5'), 'a') as f: - f.write('%s|%s|%s\n' % (recipename, os.path.relpath(fn, config.workspace_path), md5)) + with open(os.path.join(config.workspace_path, '.devtool_md5'), 'a+') as f: + md5_str = '%s|%s|%s\n' % (recipename, os.path.relpath(fn, config.workspace_path), md5) + f.seek(0, os.SEEK_SET) + if not md5_str in f.read(): + f.write(md5_str) if os.path.isdir(filename): for root, _, files in os.walk(filename):
Signature · 1 line
2.9.5
PATCH 8/10 devtool: import: new plugin to import the devtool workspace
In reply to Paul EggletonFrom: Leonardo Sandoval <[email protected]>
Takes a tar archive created by 'devtool export' and imports (untars) it into the workspace. Currently the whole tar archive is imported, there is no way to limit what is imported.
https://bugzilla.yoctoproject.org/show_bug.cgi?id=10510
[YOCTO #10510]
--- scripts/lib/devtool/__init__.py | 36 ++++++++++ scripts/lib/devtool/import.py | 144 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 scripts/lib/devtool/import.py
scripts/lib/devtool/__init__.py +36 -0
@@ -261,3 +261,39 @@ def get_bbclassextend_targets(recipefile, pn): targets.append('%s-%s' % (pn, variant)) return targets +def replace_from_file(path, old, new): + """Replace strings on a file""" + + def read_file(path): + data = None + with open(path) as f: + data = f.read() + return data + + def write_file(path, data): + if data is None: + return + wdata = data.rstrip() + "\n" + with open(path, "w") as f: + f.write(wdata) + + # In case old is None, return immediately + if old is None: + return + try: + rdata = read_file(path) + except IOError as e: + # if file does not exit, just quit, otherwise raise an exception + if e.errno == errno.ENOENT: + return + else: + raise + + old_contents = rdata.splitlines() + new_contents = [] + for old_content in old_contents: + try: + new_contents.append(old_content.replace(old, new)) + except ValueError: + pass + write_file(path, "\n".join(new_contents))
scripts/lib/devtool/import.py new file +144 -0
144 lines not on this page · raw message
Signature · 1 line
2.9.5
PATCH 9/10 recipetool: allow plugins to set PN / PV more easily
In reply to Paul EggletonPreviously if we were able to auto-determine the name from the URL, that took precedence over any name that might be set in extravalues by a plugin. Some plugins might be able to get a better idea of the name and thus we should move defaulting of the name further down after the plugins have had a chance to set it.
--- scripts/lib/recipetool/create.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
scripts/lib/recipetool/create.py +9 -7
@@ -656,13 +656,6 @@ def create_recipe(args): else: realpv = None - if srcuri and not realpv or not pn: - name_pn, name_pv = determine_from_url(srcuri) - if name_pn and not pn: - pn = name_pn - if name_pv and not realpv: - realpv = name_pv - if not srcuri: lines_before.append('# No information for SRC_URI yet (only an external source tree was specified)') lines_before.append('SRC_URI = "%s"' % srcuri)
@@ -671,6 +664,7 @@ def create_recipe(args): if srcuri and supports_srcrev(srcuri): lines_before.append('') lines_before.append('# Modify these as desired') + # Note: we have code to replace realpv further down if it gets set to some other value lines_before.append('PV = "%s+git${SRCPV}"' % (realpv or '1.0')) pv_srcpv = True if not args.autorev and srcrev == '${AUTOREV}':
@@ -750,6 +744,13 @@ def create_recipe(args): if '_' in pn: pn = pn.replace('_', '-') + if srcuri and not realpv or not pn: + name_pn, name_pv = determine_from_url(srcuri) + if name_pn and not pn: + pn = name_pn + if name_pv and not realpv: + realpv = name_pv + if not outfile: if not pn: log_error_cond('Unable to determine short program name from source tree - please specify name with -N/--name or output file name with -o/--outfile', args.devtool)
@@ -803,6 +804,7 @@ def create_recipe(args): line = line.replace(realpv, '${PV}') elif line.startswith('PV = '): if realpv: + # Replace the first part of the PV value line = re.sub('"[^+]*\+', '"%s+' % realpv, line) lines_before.append(line)
Signature · 1 line
2.9.5
PATCH 10/10 recipetool: allow plugins to set LICENSE and LIC_FILES_CHKSUM
In reply to Paul EggletonWe were being a bit prescriptive in setting LICENSE and LIC_FILES_CHKSUM. We can't always trust what's in the metadata accompanying some source which plugins will almost always be pulling from, however we do want to allow plugins to set the LICENSE and LIC_FILES_CHKSUM values. Merge what we find in our license file scan with what the plugin sends back.
Additionally, plugins can now add a "license" item to the handled list in order to inhibit the normal LICENSE / LIC_FILES_CHKSUM handling if they have already taken care of it completely.
Thanks to Mark Horn <[email protected]> for prompting, testing and fixing this patch.
--- scripts/lib/recipetool/create.py | 115 +++++++++++++++++++++++------------ scripts/lib/recipetool/create_npm.py | 44 +------------- 2 files changed, 79 insertions(+), 80 deletions(-)
scripts/lib/recipetool/create.py +77 -38
@@ -618,9 +618,10 @@ def create_recipe(args): # We need a blank line here so that patch_recipe_lines can rewind before the LICENSE comments lines_before.append('') - handled = [] - licvalues = handle_license_vars(srctree_use, lines_before, handled, extravalues, tinfoil.config_data) + # We'll come back and replace this later in handle_license_vars() + lines_before.append('##LICENSE_PLACEHOLDER##') + handled = [] classes = [] # FIXME This is kind of a hack, we probably ought to be using bitbake to do this
@@ -751,6 +752,8 @@ def create_recipe(args): if name_pv and not realpv: realpv = name_pv + licvalues = handle_license_vars(srctree_use, lines_before, handled, extravalues, tinfoil.config_data) + if not outfile: if not pn: log_error_cond('Unable to determine short program name from source tree - please specify name with -N/--name or output file name with -o/--outfile', args.devtool)
@@ -843,9 +846,6 @@ def create_recipe(args): outlines.extend(lines_after) if extravalues: - if 'LICENSE' in extravalues and not licvalues: - # Don't blow away 'CLOSED' value that comments say we set - del extravalues['LICENSE'] _, outlines = oe.recipeutils.patch_recipe_lines(outlines, extravalues, trailing_newline=False) if args.extract_to:
@@ -889,55 +889,94 @@ def check_single_file(fn, fetchuri): logger.error('Fetching "%s" returned a single HTML page - check the URL is correct and functional' % fetchuri) sys.exit(1) +def split_value(value): + if isinstance(value, str): + return value.split() + else: + return value def handle_license_vars(srctree, lines_before, handled, extravalues, d): + lichandled = [x for x in handled if x[0] == 'license'] + if lichandled: + # Someone else has already handled the license vars, just return their value + return lichandled[0][1] + licvalues = guess_license(srctree, d) + licenses = [] lic_files_chksum = [] lic_unknown = [] + lines = [] if licvalues: - licenses = [] for licvalue in licvalues: if not licvalue[0] in licenses: licenses.append(licvalue[0]) lic_files_chksum.append('file://%s;md5=%s' % (licvalue[1], licvalue[2])) if licvalue[0] == 'Unknown': lic_unknown.append(licvalue[1]) - lines_before.append('# WARNING: the following LICENSE and LIC_FILES_CHKSUM values are best guesses - it is') - lines_before.append('# your responsibility to verify that the values are complete and correct.') - if len(licvalues) > 1: - lines_before.append('#') - lines_before.append('# NOTE: multiple licenses have been detected; they have been separated with &') - lines_before.append('# in the LICENSE value for now since it is a reasonable assumption that all') - lines_before.append('# of the licenses apply. If instead there is a choice between the multiple') - lines_before.append('# licenses then you should change the value to separate the licenses with |') - lines_before.append('# instead of &. If there is any doubt, check the accompanying documentation') - lines_before.append('# to determine which situation is applicable.') if lic_unknown: - lines_before.append('#') - lines_before.append('# The following license files were not able to be identified and are') - lines_before.append('# represented as "Unknown" below, you will need to check them yourself:') + lines.append('#') + lines.append('# The following license files were not able to be identified and are') + lines.append('# represented as "Unknown" below, you will need to check them yourself:') for licfile in lic_unknown: - lines_before.append('# %s' % licfile) - lines_before.append('#') - else: - lines_before.append('# Unable to find any files that looked like license statements. Check the accompanying') - lines_before.append('# documentation and source headers and set LICENSE and LIC_FILES_CHKSUM accordingly.') - lines_before.append('#') - lines_before.append('# NOTE: LICENSE is being set to "CLOSED" to allow you to at least start building - if') - lines_before.append('# this is not accurate with respect to the licensing of the software being built (it') - lines_before.append('# will not be in most cases) you must specify the correct value before using this') - lines_before.append('# recipe for anything other than initial testing/development!') - licenses = ['CLOSED'] - pkg_license = extravalues.pop('LICENSE', None) - if pkg_license: + lines.append('# %s' % licfile) + + extra_license = split_value(extravalues.pop('LICENSE', [])) + if '&' in extra_license: + extra_license.remove('&') + if extra_license: if licenses == ['Unknown']: - lines_before.append('# NOTE: The following LICENSE value was determined from the original package metadata') - licenses = [pkg_license] + licenses = extra_license else: - lines_before.append('# NOTE: Original package metadata indicates license is: %s' % pkg_license) - lines_before.append('LICENSE = "%s"' % ' & '.join(licenses)) - lines_before.append('LIC_FILES_CHKSUM = "%s"' % ' \\\n '.join(lic_files_chksum)) - lines_before.append('') + for item in extra_license: + if item not in licenses: + licenses.append(item) + extra_lic_files_chksum = split_value(extravalues.pop('LIC_FILES_CHKSUM', [])) + for item in extra_lic_files_chksum: + if item not in lic_files_chksum: + lic_files_chksum.append(item) + + if lic_files_chksum: + # We are going to set the vars, so prepend the standard disclaimer + lines.insert(0, '# WARNING: the following LICENSE and LIC_FILES_CHKSUM values are best guesses - it is') + lines.insert(1, '# your responsibility to verify that the values are complete and correct.') + else: + # Without LIC_FILES_CHKSUM we set LICENSE = "CLOSED" to allow the + # user to get started easily + lines.append('# Unable to find any files that looked like license statements. Check the accompanying') + lines.append('# documentation and source headers and set LICENSE and LIC_FILES_CHKSUM accordingly.') + lines.append('#') + lines.append('# NOTE: LICENSE is being set to "CLOSED" to allow you to at least start building - if') + lines.append('# this is not accurate with respect to the licensing of the software being built (it') + lines.append('# will not be in most cases) you must specify the correct value before using this') + lines.append('# recipe for anything other than initial testing/development!') + licenses = ['CLOSED'] + + if extra_license and sorted(licenses) != sorted(extra_license): + lines.append('# NOTE: Original package / source metadata indicates license is: %s' % ' & '.join(extra_license)) + + if len(licenses) > 1: + lines.append('#') + lines.append('# NOTE: multiple licenses have been detected; they have been separated with &') + lines.append('# in the LICENSE value for now since it is a reasonable assumption that all') + lines.append('# of the licenses apply. If instead there is a choice between the multiple') + lines.append('# licenses then you should change the value to separate the licenses with |') + lines.append('# instead of &. If there is any doubt, check the accompanying documentation') + lines.append('# to determine which situation is applicable.') + + lines.append('LICENSE = "%s"' % ' & '.join(licenses)) + lines.append('LIC_FILES_CHKSUM = "%s"' % ' \\\n '.join(lic_files_chksum)) + lines.append('') + + # Replace the placeholder so we get the values in the right place in the recipe file + try: + pos = lines_before.index('##LICENSE_PLACEHOLDER##') + except ValueError: + pos = -1 + if pos == -1: + lines_before.extend(lines) + else: + lines_before[pos:pos+1] = lines + handled.append(('license', licvalues)) return licvalues
scripts/lib/recipetool/create_npm.py +2 -42
62 lines not on this page · raw message
Signature · 1 line
2.9.5