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