diff options
author | Paul Eggleton <paul.eggleton@linux.intel.com> | 2016-10-04 22:31:16 +1300 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-10-05 10:10:11 +0100 |
commit | 18caacae069a025662fcdd96b846857fc3107e41 (patch) | |
tree | 3fbd57297f2548b45ee0a87ff80dfb79941674fe /scripts | |
parent | ee697d84ba2a83b196bd3b927a0b6047464f5292 (diff) | |
download | poky-18caacae069a025662fcdd96b846857fc3107e41.tar.gz |
devtool: add: build nodejs-native if npm is needed and not available
If the user runs devtool add on an npm:// URL (or source tree that uses
node.js), and npm is not available, just build nodejs-native instead of
telling the user they need to do it; if that fails because there isn't
any such recipe (which would be the default, since it's not in OE-Core)
then produce a slightly more readable error message hinting at what the
user needs to do.
Note that this forces the use of nodejs-native rather than npm on the
host - this makes sense for two reasons: (1) we need it to be compatible
with nodejs for the target, and (2) we have to have a recipe for that
anyway, so allowing you to avoid having a recipe for the native version
isn't really beneficial.
There's a bit of a hack in here in order to allow this - for node.js
sources that aren't fetched via npm we don't know that they are that
until we've fetched and unpacked them, by which time we're inside
recipetool and have an active tinfoil instance that will prevent bitbake
being run. To avoid this being an issue, we allow recipetool to get to
the point where we know we need npm and then exit with a specific exit
code, at which point devtool can try to build it and then if that
succeeds, it will re-execute recipetool. This is definitely not ideal,
but it can't really be refactored and done properly until we do the
tinfoil2 refactoring; in the mean time though we still want to be
helpful to the user.
Fixes [YOCTO #10337].
(From OE-Core rev: f40662bde5aab158c4e4c3c3ff5e68665a4194a5)
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/lib/devtool/__init__.py | 29 | ||||
-rw-r--r-- | scripts/lib/devtool/standard.py | 31 | ||||
-rw-r--r-- | scripts/lib/recipetool/create.py | 10 | ||||
-rw-r--r-- | scripts/lib/recipetool/create_npm.py | 4 |
4 files changed, 60 insertions, 14 deletions
diff --git a/scripts/lib/devtool/__init__.py b/scripts/lib/devtool/__init__.py index b432e3d44e..e675133f63 100644 --- a/scripts/lib/devtool/__init__.py +++ b/scripts/lib/devtool/__init__.py | |||
@@ -259,3 +259,32 @@ def get_bbclassextend_targets(recipefile, pn): | |||
259 | elif variant in ['native', 'cross', 'crosssdk']: | 259 | elif variant in ['native', 'cross', 'crosssdk']: |
260 | targets.append('%s-%s' % (pn, variant)) | 260 | targets.append('%s-%s' % (pn, variant)) |
261 | return targets | 261 | return targets |
262 | |||
263 | def ensure_npm(config, basepath, fixed_setup=False): | ||
264 | """ | ||
265 | Ensure that npm is available and either build it or show a | ||
266 | reasonable error message | ||
267 | """ | ||
268 | tinfoil = setup_tinfoil(config_only=True, basepath=basepath) | ||
269 | try: | ||
270 | nativepath = tinfoil.config_data.getVar('STAGING_BINDIR_NATIVE', True) | ||
271 | finally: | ||
272 | tinfoil.shutdown() | ||
273 | |||
274 | npmpath = os.path.join(nativepath, 'npm') | ||
275 | if not os.path.exists(npmpath): | ||
276 | logger.info('Building nodejs-native') | ||
277 | try: | ||
278 | exec_build_env_command(config.init_path, basepath, | ||
279 | 'bitbake -q nodejs-native', watch=True) | ||
280 | except bb.process.ExecutionError as e: | ||
281 | if "Nothing PROVIDES 'nodejs-native'" in e.stdout: | ||
282 | if fixed_setup: | ||
283 | msg = 'nodejs-native is required for npm but is not available within this SDK' | ||
284 | else: | ||
285 | msg = 'nodejs-native is required for npm but is not available - you will likely need to add a layer that provides nodejs' | ||
286 | raise DevtoolError(msg) | ||
287 | else: | ||
288 | raise | ||
289 | if not os.path.exists(npmpath): | ||
290 | raise DevtoolError('Built nodejs-native but npm binary still could not be found at %s' % npmpath) | ||
diff --git a/scripts/lib/devtool/standard.py b/scripts/lib/devtool/standard.py index 02ed23574b..4b9b173156 100644 --- a/scripts/lib/devtool/standard.py +++ b/scripts/lib/devtool/standard.py | |||
@@ -30,7 +30,7 @@ import errno | |||
30 | import glob | 30 | import glob |
31 | import filecmp | 31 | import filecmp |
32 | from collections import OrderedDict | 32 | from collections import OrderedDict |
33 | from devtool import exec_build_env_command, setup_tinfoil, check_workspace_recipe, use_external_build, setup_git_repo, recipe_to_append, get_bbclassextend_targets, DevtoolError | 33 | from devtool import exec_build_env_command, setup_tinfoil, check_workspace_recipe, use_external_build, setup_git_repo, recipe_to_append, get_bbclassextend_targets, ensure_npm, DevtoolError |
34 | from devtool import parse_recipe | 34 | from devtool import parse_recipe |
35 | 35 | ||
36 | logger = logging.getLogger('devtool') | 36 | logger = logging.getLogger('devtool') |
@@ -128,6 +128,9 @@ def add(args, config, basepath, workspace): | |||
128 | color = args.color | 128 | color = args.color |
129 | extracmdopts = '' | 129 | extracmdopts = '' |
130 | if args.fetchuri: | 130 | if args.fetchuri: |
131 | if args.fetchuri.startswith('npm://'): | ||
132 | ensure_npm(config, basepath, args.fixed_setup) | ||
133 | |||
131 | source = args.fetchuri | 134 | source = args.fetchuri |
132 | if srctree: | 135 | if srctree: |
133 | extracmdopts += ' -x %s' % srctree | 136 | extracmdopts += ' -x %s' % srctree |
@@ -150,13 +153,23 @@ def add(args, config, basepath, workspace): | |||
150 | 153 | ||
151 | tempdir = tempfile.mkdtemp(prefix='devtool') | 154 | tempdir = tempfile.mkdtemp(prefix='devtool') |
152 | try: | 155 | try: |
153 | try: | 156 | while True: |
154 | stdout, _ = exec_build_env_command(config.init_path, basepath, 'recipetool --color=%s create -o %s "%s" %s' % (color, tempdir, source, extracmdopts)) | 157 | try: |
155 | except bb.process.ExecutionError as e: | 158 | stdout, _ = exec_build_env_command(config.init_path, basepath, 'recipetool --color=%s create -o %s "%s" %s' % (color, tempdir, source, extracmdopts)) |
156 | if e.exitcode == 15: | 159 | except bb.process.ExecutionError as e: |
157 | raise DevtoolError('Could not auto-determine recipe name, please specify it on the command line') | 160 | if e.exitcode == 14: |
158 | else: | 161 | # FIXME this is a horrible hack that is unfortunately |
159 | raise DevtoolError('Command \'%s\' failed:\n%s' % (e.command, e.stdout)) | 162 | # necessary due to the fact that we can't run bitbake from |
163 | # inside recipetool since recipetool keeps tinfoil active | ||
164 | # with references to it throughout the code, so we have | ||
165 | # to exit out and come back here to do it. | ||
166 | ensure_npm(config, basepath, args.fixed_setup) | ||
167 | continue | ||
168 | elif e.exitcode == 15: | ||
169 | raise DevtoolError('Could not auto-determine recipe name, please specify it on the command line') | ||
170 | else: | ||
171 | raise DevtoolError('Command \'%s\' failed:\n%s' % (e.command, e.stdout)) | ||
172 | break | ||
160 | 173 | ||
161 | recipes = glob.glob(os.path.join(tempdir, '*.bb')) | 174 | recipes = glob.glob(os.path.join(tempdir, '*.bb')) |
162 | if recipes: | 175 | if recipes: |
@@ -1567,7 +1580,7 @@ def register_commands(subparsers, context): | |||
1567 | parser_add.add_argument('--binary', '-b', help='Treat the source tree as something that should be installed verbatim (no compilation, same directory structure). Useful with binary packages e.g. RPMs.', action='store_true') | 1580 | parser_add.add_argument('--binary', '-b', help='Treat the source tree as something that should be installed verbatim (no compilation, same directory structure). Useful with binary packages e.g. RPMs.', action='store_true') |
1568 | parser_add.add_argument('--also-native', help='Also add native variant (i.e. support building recipe for the build host as well as the target machine)', action='store_true') | 1581 | parser_add.add_argument('--also-native', help='Also add native variant (i.e. support building recipe for the build host as well as the target machine)', action='store_true') |
1569 | parser_add.add_argument('--src-subdir', help='Specify subdirectory within source tree to use', metavar='SUBDIR') | 1582 | parser_add.add_argument('--src-subdir', help='Specify subdirectory within source tree to use', metavar='SUBDIR') |
1570 | parser_add.set_defaults(func=add) | 1583 | parser_add.set_defaults(func=add, fixed_setup=context.fixed_setup) |
1571 | 1584 | ||
1572 | parser_modify = subparsers.add_parser('modify', help='Modify the source for an existing recipe', | 1585 | parser_modify = subparsers.add_parser('modify', help='Modify the source for an existing recipe', |
1573 | description='Sets up the build environment to modify the source for an existing recipe. The default behaviour is to extract the source being fetched by the recipe into a git tree so you can work on it; alternatively if you already have your own pre-prepared source tree you can specify -n/--no-extract.', | 1586 | description='Sets up the build environment to modify the source for an existing recipe. The default behaviour is to extract the source being fetched by the recipe into a git tree so you can work on it; alternatively if you already have your own pre-prepared source tree you can specify -n/--no-extract.', |
diff --git a/scripts/lib/recipetool/create.py b/scripts/lib/recipetool/create.py index 9b31fe92d7..d427d32062 100644 --- a/scripts/lib/recipetool/create.py +++ b/scripts/lib/recipetool/create.py | |||
@@ -406,10 +406,7 @@ def create_recipe(args): | |||
406 | srctree = tempsrc | 406 | srctree = tempsrc |
407 | if fetchuri.startswith('npm://'): | 407 | if fetchuri.startswith('npm://'): |
408 | # Check if npm is available | 408 | # Check if npm is available |
409 | npm = bb.utils.which(tinfoil.config_data.getVar('PATH', True), 'npm') | 409 | check_npm(tinfoil.config_data) |
410 | if not npm: | ||
411 | logger.error('npm:// URL requested but npm is not available - you need to either build nodejs-native or install npm using your package manager') | ||
412 | sys.exit(1) | ||
413 | logger.info('Fetching %s...' % srcuri) | 410 | logger.info('Fetching %s...' % srcuri) |
414 | try: | 411 | try: |
415 | checksums = scriptutils.fetch_uri(tinfoil.config_data, fetchuri, srctree, srcrev) | 412 | checksums = scriptutils.fetch_uri(tinfoil.config_data, fetchuri, srctree, srcrev) |
@@ -1076,6 +1073,11 @@ def convert_rpm_xml(xmlfile): | |||
1076 | return values | 1073 | return values |
1077 | 1074 | ||
1078 | 1075 | ||
1076 | def check_npm(d): | ||
1077 | if not os.path.exists(os.path.join(d.getVar('STAGING_BINDIR_NATIVE', True), 'npm')): | ||
1078 | logger.error('npm required to process specified source, but npm is not available - you need to build nodejs-native first') | ||
1079 | sys.exit(14) | ||
1080 | |||
1079 | def register_commands(subparsers): | 1081 | def register_commands(subparsers): |
1080 | parser_create = subparsers.add_parser('create', | 1082 | parser_create = subparsers.add_parser('create', |
1081 | help='Create a new recipe', | 1083 | help='Create a new recipe', |
diff --git a/scripts/lib/recipetool/create_npm.py b/scripts/lib/recipetool/create_npm.py index e794614978..7bb844cb0c 100644 --- a/scripts/lib/recipetool/create_npm.py +++ b/scripts/lib/recipetool/create_npm.py | |||
@@ -21,7 +21,7 @@ import subprocess | |||
21 | import tempfile | 21 | import tempfile |
22 | import shutil | 22 | import shutil |
23 | import json | 23 | import json |
24 | from recipetool.create import RecipeHandler, split_pkg_licenses, handle_license_vars | 24 | from recipetool.create import RecipeHandler, split_pkg_licenses, handle_license_vars, check_npm |
25 | 25 | ||
26 | logger = logging.getLogger('recipetool') | 26 | logger = logging.getLogger('recipetool') |
27 | 27 | ||
@@ -157,6 +157,8 @@ class NpmRecipeHandler(RecipeHandler): | |||
157 | 157 | ||
158 | files = RecipeHandler.checkfiles(srctree, ['package.json']) | 158 | files = RecipeHandler.checkfiles(srctree, ['package.json']) |
159 | if files: | 159 | if files: |
160 | check_npm(tinfoil.config_data) | ||
161 | |||
160 | data = read_package_json(files[0]) | 162 | data = read_package_json(files[0]) |
161 | if 'name' in data and 'version' in data: | 163 | if 'name' in data and 'version' in data: |
162 | extravalues['PN'] = data['name'] | 164 | extravalues['PN'] = data['name'] |