1# Development tool - search command plugin
2#
3# Copyright (C) 2015 Intel Corporation
4#
5# SPDX-License-Identifier: GPL-2.0-only
6#
7
8"""Devtool search plugin"""
9
10import os
11import bb
12import logging
13import argparse
14import re
15from devtool import setup_tinfoil, parse_recipe, DevtoolError
16
17logger = logging.getLogger('devtool')
18
19def search(args, config, basepath, workspace):
20    """Entry point for the devtool 'search' subcommand"""
21
22    tinfoil = setup_tinfoil(config_only=False, basepath=basepath)
23    try:
24        pkgdata_dir = tinfoil.config_data.getVar('PKGDATA_DIR')
25        defsummary = tinfoil.config_data.getVar('SUMMARY', False) or ''
26
27        keyword_rc = re.compile(args.keyword)
28
29        def print_match(pn):
30            rd = parse_recipe(config, tinfoil, pn, True)
31            if not rd:
32                return
33            summary = rd.getVar('SUMMARY')
34            if summary == rd.expand(defsummary):
35                summary = ''
36            print("%s  %s" % (pn.ljust(20), summary))
37
38
39        matches = []
40        if os.path.exists(pkgdata_dir):
41            for fn in os.listdir(pkgdata_dir):
42                pfn = os.path.join(pkgdata_dir, fn)
43                if not os.path.isfile(pfn):
44                    continue
45
46                packages = []
47                match = False
48                if keyword_rc.search(fn):
49                    match = True
50
51                if not match:
52                    with open(pfn, 'r') as f:
53                        for line in f:
54                            if line.startswith('PACKAGES:'):
55                                packages = line.split(':', 1)[1].strip().split()
56
57                    for pkg in packages:
58                        if keyword_rc.search(pkg):
59                            match = True
60                            break
61                        if os.path.exists(os.path.join(pkgdata_dir, 'runtime', pkg + '.packaged')):
62                            with open(os.path.join(pkgdata_dir, 'runtime', pkg), 'r') as f:
63                                for line in f:
64                                    if ': ' in line:
65                                        splitline = line.split(': ', 1)
66                                        key = splitline[0]
67                                        value = splitline[1].strip()
68                                    key = key.replace(":" + pkg, "")
69                                    if key in ['PKG', 'DESCRIPTION', 'FILES_INFO', 'FILERPROVIDES']:
70                                        if keyword_rc.search(value):
71                                            match = True
72                                            break
73                if match:
74                    print_match(fn)
75                    matches.append(fn)
76        else:
77            logger.warning('Package data is not available, results may be limited')
78
79        for recipe in tinfoil.all_recipes():
80            if args.fixed_setup and 'nativesdk' in recipe.inherits():
81                continue
82
83            match = False
84            if keyword_rc.search(recipe.pn):
85                match = True
86            else:
87                for prov in recipe.provides:
88                    if keyword_rc.search(prov):
89                        match = True
90                        break
91                if not match:
92                    for rprov in recipe.rprovides:
93                        if keyword_rc.search(rprov):
94                            match = True
95                            break
96            if match and not recipe.pn in matches:
97                print_match(recipe.pn)
98    finally:
99        tinfoil.shutdown()
100
101    return 0
102
103def register_commands(subparsers, context):
104    """Register devtool subcommands from this plugin"""
105    parser_search = subparsers.add_parser('search', help='Search available recipes',
106                                            description='Searches for available recipes. Matches on recipe name, package name, description and installed files, and prints the recipe name and summary on match.',
107                                            group='info')
108    parser_search.add_argument('keyword', help='Keyword to search for (regular expression syntax allowed, use quotes to avoid shell expansion)')
109    parser_search.set_defaults(func=search, no_workspace=True, fixed_setup=context.fixed_setup)
110