1#
2# BitBake Toaster Implementation
3#
4# Copyright (C) 2015        Intel Corporation
5#
6# SPDX-License-Identifier: GPL-2.0-only
7#
8
9import subprocess
10
11from toastergui.widgets import ToasterTypeAhead
12from orm.models import Project
13from django.urls import reverse
14from django.core.cache import cache
15
16
17class LayersTypeAhead(ToasterTypeAhead):
18    """ Typeahead for layers available and not added in the current project's
19    configuration """
20
21    def apply_search(self, search_term, prj, request):
22        layers = prj.get_all_compatible_layer_versions()
23        layers = layers.order_by('layer__name')
24
25        # Unlike the other typeaheads we also don't want to show suggestions
26        # for layers already in the project unless required such as when adding
27        # layerdeps to a new layer.
28        if "include_added" in request.GET and \
29           request.GET['include_added'] != "true":
30            layers = layers.exclude(
31                pk__in=prj.get_project_layer_versions(pk=True))
32
33        primary_results = layers.filter(layer__name__istartswith=search_term)
34        secondary_results = layers.filter(
35            layer__name__icontains=search_term).exclude(
36                pk__in=primary_results)
37
38        results = []
39
40        for layer_version in list(primary_results) + list(secondary_results):
41            vcs_reference = layer_version.get_vcs_reference()
42
43            detail = "[ %s | %s ]" % (layer_version.layer.vcs_url,
44                                      vcs_reference)
45            needed_fields = {
46                'id': layer_version.pk,
47                'name': layer_version.layer.name,
48                'layerdetailurl': layer_version.get_detailspage_url(prj.pk),
49                'xhrLayerUrl': reverse('xhr_layer',
50                                       args=(prj.pk, layer_version.pk)),
51                'vcs_url': layer_version.layer.vcs_url,
52                'vcs_reference': vcs_reference,
53                'detail': detail,
54                'local_source_dir': layer_version.layer.local_source_dir,
55            }
56
57            results.append(needed_fields)
58
59        return results
60
61
62class MachinesTypeAhead(ToasterTypeAhead):
63    """ Typeahead for all the machines available in the current project's
64    configuration """
65
66    def apply_search(self, search_term, prj, request):
67        machines = prj.get_available_machines()
68        machines = machines.order_by("name")
69
70        primary_results = machines.filter(name__istartswith=search_term)
71        secondary_results = machines.filter(
72            name__icontains=search_term).exclude(pk__in=primary_results)
73        tertiary_results = machines.filter(
74            layer_version__layer__name__icontains=search_term).exclude(
75                pk__in=primary_results).exclude(pk__in=secondary_results)
76
77        results = []
78
79        for machine in list(primary_results) + list(secondary_results) + \
80                list(tertiary_results):
81
82            detail = "[ %s ]" % (machine.layer_version.layer.name)
83            needed_fields = {
84                'id': machine.pk,
85                'name': machine.name,
86                'detail': detail,
87            }
88
89            results.append(needed_fields)
90        return results
91
92
93class DistrosTypeAhead(ToasterTypeAhead):
94    """ Typeahead for all the distros available in the current project's
95    configuration """
96    def __init__(self):
97        super(DistrosTypeAhead, self).__init__()
98
99    def apply_search(self, search_term, prj, request):
100        distros = prj.get_available_distros()
101        distros = distros.order_by("name")
102
103        primary_results = distros.filter(name__istartswith=search_term)
104        secondary_results = distros.filter(name__icontains=search_term).exclude(pk__in=primary_results)
105        tertiary_results = distros.filter(layer_version__layer__name__icontains=search_term).exclude(pk__in=primary_results).exclude(pk__in=secondary_results)
106
107        results = []
108
109        for distro in list(primary_results) + list(secondary_results) + list(tertiary_results):
110
111            detail = "[ %s ]" % (distro.layer_version.layer.name)
112            needed_fields = {
113                'id' : distro.pk,
114                'name' : distro.name,
115                'detail' : detail,
116            }
117
118            results.append(needed_fields)
119
120        return results
121
122
123class RecipesTypeAhead(ToasterTypeAhead):
124    """ Typeahead for all the recipes available in the current project's
125    configuration """
126    def apply_search(self, search_term, prj, request):
127        recipes = prj.get_available_recipes()
128        recipes = recipes.order_by("name")
129
130        primary_results = recipes.filter(name__istartswith=search_term)
131        secondary_results = recipes.filter(
132            name__icontains=search_term).exclude(pk__in=primary_results)
133        tertiary_results = recipes.filter(
134            layer_version__layer__name__icontains=search_term).exclude(
135                pk__in=primary_results).exclude(pk__in=secondary_results)
136
137        results = []
138
139        for recipe in list(primary_results) + list(secondary_results) + \
140                list(tertiary_results):
141
142            detail = "[ %s ]" % (recipe.layer_version.layer.name)
143            needed_fields = {
144                'id': recipe.pk,
145                'name': recipe.name,
146                'detail': detail,
147            }
148
149            results.append(needed_fields)
150
151        return results
152
153
154class ProjectsTypeAhead(ToasterTypeAhead):
155    """ Typeahead for all the projects, except for command line builds """
156    def apply_search(self, search_term, prj, request):
157        projects = Project.objects.exclude(is_default=True).order_by("name")
158
159        primary_results = projects.filter(name__istartswith=search_term)
160        secondary_results = projects.filter(
161            name__icontains=search_term).exclude(pk__in=primary_results)
162
163        results = []
164
165        for project in list(primary_results) + list(secondary_results):
166            needed_fields = {
167                'id': project.pk,
168                'name': project.name,
169                'detail': "",
170                'projectPageUrl': reverse('project', args=(project.pk,))
171            }
172
173            results.append(needed_fields)
174
175        return results
176
177
178class GitRevisionTypeAhead(ToasterTypeAhead):
179    def apply_search(self, search_term, prj, request):
180        results = []
181        git_url = request.GET.get('git_url')
182        ls_remote = cache.get(git_url)
183
184        if ls_remote is None:
185            ls_remote = subprocess.check_output(['git', 'ls-remote', git_url],
186                                                universal_newlines=True)
187            ls_remote = ls_remote.splitlines()
188            # Avoid fetching the list of git refs on each new input
189            cache.set(git_url, ls_remote, 120)
190
191        for rev in ls_remote:
192            git_rev = str(rev).split("/")[-1:][0]
193            # "HEAD" has a special meaning in Toaster...  YOCTO #9924
194            if "HEAD" in git_rev:
195                continue
196
197            if git_rev.startswith(search_term):
198                results.append({'name': git_rev,
199                                'detail': '[ %s ]' % str(rev)})
200
201        return results
202