1eb8dc403SDave Cobbley# 2eb8dc403SDave Cobbley# BitBake Toaster Implementation 3eb8dc403SDave Cobbley# 4eb8dc403SDave Cobbley# Copyright (C) 2015 Intel Corporation 5eb8dc403SDave Cobbley# 6c342db35SBrad Bishop# SPDX-License-Identifier: GPL-2.0-only 7eb8dc403SDave Cobbley# 8eb8dc403SDave Cobbley 9eb8dc403SDave Cobbleyfrom toastergui.widgets import ToasterTable 10*82c905dcSAndrew Geisslerfrom orm.models import Recipe, ProjectLayer, Layer_Version, Project 11eb8dc403SDave Cobbleyfrom orm.models import CustomImageRecipe, Package, Target, Build, LogMessage, Task 12eb8dc403SDave Cobbleyfrom orm.models import CustomImagePackage, Package_DependencyManager 13*82c905dcSAndrew Geisslerfrom django.db.models import Q, Sum, Count, When, Case, Value, IntegerField 14eb8dc403SDave Cobbley 15eb8dc403SDave Cobbleyfrom toastergui.tablefilter import TableFilter 16eb8dc403SDave Cobbleyfrom toastergui.tablefilter import TableFilterActionToggle 17eb8dc403SDave Cobbleyfrom toastergui.tablefilter import TableFilterActionDateRange 18eb8dc403SDave Cobbleyfrom toastergui.tablefilter import TableFilterActionDay 19eb8dc403SDave Cobbley 201a4b7ee2SBrad Bishopimport os 211a4b7ee2SBrad Bishop 22eb8dc403SDave Cobbleyclass ProjectFilters(object): 23eb8dc403SDave Cobbley @staticmethod 24eb8dc403SDave Cobbley def in_project(project_layers): 25eb8dc403SDave Cobbley return Q(layer_version__in=project_layers) 26eb8dc403SDave Cobbley 27eb8dc403SDave Cobbley @staticmethod 28eb8dc403SDave Cobbley def not_in_project(project_layers): 29eb8dc403SDave Cobbley return ~(ProjectFilters.in_project(project_layers)) 30eb8dc403SDave Cobbley 31eb8dc403SDave Cobbleyclass LayersTable(ToasterTable): 32eb8dc403SDave Cobbley """Table of layers in Toaster""" 33eb8dc403SDave Cobbley 34eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 35eb8dc403SDave Cobbley super(LayersTable, self).__init__(*args, **kwargs) 36eb8dc403SDave Cobbley self.default_orderby = "layer__name" 37eb8dc403SDave Cobbley self.title = "Compatible layers" 38eb8dc403SDave Cobbley 39eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 40eb8dc403SDave Cobbley context = super(LayersTable, self).get_context_data(**kwargs) 41eb8dc403SDave Cobbley 42eb8dc403SDave Cobbley project = Project.objects.get(pk=kwargs['pid']) 43eb8dc403SDave Cobbley context['project'] = project 44eb8dc403SDave Cobbley 45eb8dc403SDave Cobbley return context 46eb8dc403SDave Cobbley 47eb8dc403SDave Cobbley def setup_filters(self, *args, **kwargs): 48eb8dc403SDave Cobbley project = Project.objects.get(pk=kwargs['pid']) 49eb8dc403SDave Cobbley self.project_layers = ProjectLayer.objects.filter(project=project) 50eb8dc403SDave Cobbley 51eb8dc403SDave Cobbley in_current_project_filter = TableFilter( 52eb8dc403SDave Cobbley "in_current_project", 53eb8dc403SDave Cobbley "Filter by project layers" 54eb8dc403SDave Cobbley ) 55eb8dc403SDave Cobbley 56eb8dc403SDave Cobbley criteria = Q(projectlayer__in=self.project_layers) 57eb8dc403SDave Cobbley 58eb8dc403SDave Cobbley in_project_action = TableFilterActionToggle( 59eb8dc403SDave Cobbley "in_project", 60eb8dc403SDave Cobbley "Layers added to this project", 61eb8dc403SDave Cobbley criteria 62eb8dc403SDave Cobbley ) 63eb8dc403SDave Cobbley 64eb8dc403SDave Cobbley not_in_project_action = TableFilterActionToggle( 65eb8dc403SDave Cobbley "not_in_project", 66eb8dc403SDave Cobbley "Layers not added to this project", 67eb8dc403SDave Cobbley ~criteria 68eb8dc403SDave Cobbley ) 69eb8dc403SDave Cobbley 70eb8dc403SDave Cobbley in_current_project_filter.add_action(in_project_action) 71eb8dc403SDave Cobbley in_current_project_filter.add_action(not_in_project_action) 72eb8dc403SDave Cobbley self.add_filter(in_current_project_filter) 73eb8dc403SDave Cobbley 74eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 75eb8dc403SDave Cobbley prj = Project.objects.get(pk = kwargs['pid']) 76eb8dc403SDave Cobbley compatible_layers = prj.get_all_compatible_layer_versions() 77eb8dc403SDave Cobbley 78eb8dc403SDave Cobbley self.static_context_extra['current_layers'] = \ 79eb8dc403SDave Cobbley prj.get_project_layer_versions(pk=True) 80eb8dc403SDave Cobbley 81eb8dc403SDave Cobbley self.queryset = compatible_layers.order_by(self.default_orderby) 82eb8dc403SDave Cobbley 83eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 84eb8dc403SDave Cobbley 85eb8dc403SDave Cobbley layer_link_template = ''' 86eb8dc403SDave Cobbley <a href="{% url 'layerdetails' extra.pid data.id %}"> 87eb8dc403SDave Cobbley {{data.layer.name}} 88eb8dc403SDave Cobbley </a> 89eb8dc403SDave Cobbley ''' 90eb8dc403SDave Cobbley 91eb8dc403SDave Cobbley self.add_column(title="Layer", 92eb8dc403SDave Cobbley hideable=False, 93eb8dc403SDave Cobbley orderable=True, 94eb8dc403SDave Cobbley static_data_name="layer__name", 95eb8dc403SDave Cobbley static_data_template=layer_link_template) 96eb8dc403SDave Cobbley 97eb8dc403SDave Cobbley self.add_column(title="Summary", 98eb8dc403SDave Cobbley field_name="layer__summary") 99eb8dc403SDave Cobbley 100eb8dc403SDave Cobbley git_url_template = ''' 101eb8dc403SDave Cobbley <a href="{% url 'layerdetails' extra.pid data.id %}"> 102eb8dc403SDave Cobbley {% if data.layer.local_source_dir %} 103eb8dc403SDave Cobbley <code>{{data.layer.local_source_dir}}</code> 104eb8dc403SDave Cobbley {% else %} 105eb8dc403SDave Cobbley <code>{{data.layer.vcs_url}}</code> 106eb8dc403SDave Cobbley </a> 107eb8dc403SDave Cobbley {% endif %} 108eb8dc403SDave Cobbley {% if data.get_vcs_link_url %} 109eb8dc403SDave Cobbley <a target="_blank" href="{{ data.get_vcs_link_url }}"> 110eb8dc403SDave Cobbley <span class="glyphicon glyphicon-new-window"></span> 111eb8dc403SDave Cobbley </a> 112eb8dc403SDave Cobbley {% endif %} 113eb8dc403SDave Cobbley ''' 114eb8dc403SDave Cobbley 115eb8dc403SDave Cobbley self.add_column(title="Layer source code location", 116eb8dc403SDave Cobbley help_text="A Git repository or an absolute path to a directory", 117eb8dc403SDave Cobbley hidden=True, 118eb8dc403SDave Cobbley static_data_name="layer__vcs_url", 119eb8dc403SDave Cobbley static_data_template=git_url_template) 120eb8dc403SDave Cobbley 121eb8dc403SDave Cobbley git_dir_template = ''' 122eb8dc403SDave Cobbley {% if data.layer.local_source_dir %} 123eb8dc403SDave Cobbley <span class="text-muted">Not applicable</span> 124eb8dc403SDave Cobbley <span class="glyphicon glyphicon-question-sign get-help" data-original-title="" title="The source code of {{data.layer.name}} is not in a Git repository, so there is no subdirectory associated with it"> </span> 125eb8dc403SDave Cobbley {% else %} 126eb8dc403SDave Cobbley <a href="{% url 'layerdetails' extra.pid data.id %}"> 127eb8dc403SDave Cobbley <code>{{data.dirpath}}</code> 128eb8dc403SDave Cobbley </a> 129eb8dc403SDave Cobbley {% endif %} 130eb8dc403SDave Cobbley {% if data.dirpath and data.get_vcs_dirpath_link_url %} 131eb8dc403SDave Cobbley <a target="_blank" href="{{ data.get_vcs_dirpath_link_url }}"> 132eb8dc403SDave Cobbley <span class="glyphicon glyphicon-new-window"></span> 133eb8dc403SDave Cobbley </a> 134eb8dc403SDave Cobbley {% endif %}''' 135eb8dc403SDave Cobbley 136eb8dc403SDave Cobbley self.add_column(title="Subdirectory", 137eb8dc403SDave Cobbley help_text="The layer directory within the Git repository", 138eb8dc403SDave Cobbley hidden=True, 139eb8dc403SDave Cobbley static_data_name="git_subdir", 140eb8dc403SDave Cobbley static_data_template=git_dir_template) 141eb8dc403SDave Cobbley 142eb8dc403SDave Cobbley revision_template = ''' 143eb8dc403SDave Cobbley {% if data.layer.local_source_dir %} 144eb8dc403SDave Cobbley <span class="text-muted">Not applicable</span> 145eb8dc403SDave Cobbley <span class="glyphicon glyphicon-question-sign get-help" data-original-title="" title="The source code of {{data.layer.name}} is not in a Git repository, so there is no revision associated with it"> </span> 146eb8dc403SDave Cobbley {% else %} 147eb8dc403SDave Cobbley {% with vcs_ref=data.get_vcs_reference %} 148eb8dc403SDave Cobbley {% include 'snippets/gitrev_popover.html' %} 149eb8dc403SDave Cobbley {% endwith %} 150eb8dc403SDave Cobbley {% endif %} 151eb8dc403SDave Cobbley ''' 152eb8dc403SDave Cobbley 153eb8dc403SDave Cobbley self.add_column(title="Git revision", 154eb8dc403SDave Cobbley help_text="The Git branch, tag or commit. For the layers from the OpenEmbedded layer source, the revision is always the branch compatible with the Yocto Project version you selected for this project", 155eb8dc403SDave Cobbley static_data_name="revision", 156eb8dc403SDave Cobbley static_data_template=revision_template) 157eb8dc403SDave Cobbley 158eb8dc403SDave Cobbley deps_template = ''' 159eb8dc403SDave Cobbley {% with ods=data.dependencies.all%} 160eb8dc403SDave Cobbley {% if ods.count %} 161eb8dc403SDave Cobbley <a class="btn btn-default" title="<a href='{% url "layerdetails" extra.pid data.id %}'>{{data.layer.name}}</a> dependencies" 162eb8dc403SDave Cobbley data-content="<ul class='list-unstyled'> 163eb8dc403SDave Cobbley {% for i in ods%} 164eb8dc403SDave Cobbley <li><a href='{% url "layerdetails" extra.pid i.depends_on.pk %}'>{{i.depends_on.layer.name}}</a></li> 165eb8dc403SDave Cobbley {% endfor %} 166eb8dc403SDave Cobbley </ul>"> 167eb8dc403SDave Cobbley {{ods.count}} 168eb8dc403SDave Cobbley </a> 169eb8dc403SDave Cobbley {% endif %} 170eb8dc403SDave Cobbley {% endwith %} 171eb8dc403SDave Cobbley ''' 172eb8dc403SDave Cobbley 173eb8dc403SDave Cobbley self.add_column(title="Dependencies", 174eb8dc403SDave Cobbley help_text="Other layers a layer depends upon", 175eb8dc403SDave Cobbley static_data_name="dependencies", 176eb8dc403SDave Cobbley static_data_template=deps_template) 177eb8dc403SDave Cobbley 178eb8dc403SDave Cobbley self.add_column(title="Add | Remove", 179eb8dc403SDave Cobbley help_text="Add or remove layers to / from your project", 180eb8dc403SDave Cobbley hideable=False, 181eb8dc403SDave Cobbley filter_name="in_current_project", 182eb8dc403SDave Cobbley static_data_name="add-del-layers", 183eb8dc403SDave Cobbley static_data_template='{% include "layer_btn.html" %}') 184eb8dc403SDave Cobbley 185eb8dc403SDave Cobbley 186eb8dc403SDave Cobbleyclass MachinesTable(ToasterTable): 187eb8dc403SDave Cobbley """Table of Machines in Toaster""" 188eb8dc403SDave Cobbley 189eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 190eb8dc403SDave Cobbley super(MachinesTable, self).__init__(*args, **kwargs) 191eb8dc403SDave Cobbley self.empty_state = "Toaster has no machine information for this project. Sadly, machine information cannot be obtained from builds, so this page will remain empty." 192eb8dc403SDave Cobbley self.title = "Compatible machines" 193eb8dc403SDave Cobbley self.default_orderby = "name" 194eb8dc403SDave Cobbley 195eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 196eb8dc403SDave Cobbley context = super(MachinesTable, self).get_context_data(**kwargs) 197eb8dc403SDave Cobbley context['project'] = Project.objects.get(pk=kwargs['pid']) 198eb8dc403SDave Cobbley return context 199eb8dc403SDave Cobbley 200eb8dc403SDave Cobbley def setup_filters(self, *args, **kwargs): 201eb8dc403SDave Cobbley project = Project.objects.get(pk=kwargs['pid']) 202eb8dc403SDave Cobbley 203eb8dc403SDave Cobbley in_current_project_filter = TableFilter( 204eb8dc403SDave Cobbley "in_current_project", 205eb8dc403SDave Cobbley "Filter by project machines" 206eb8dc403SDave Cobbley ) 207eb8dc403SDave Cobbley 208eb8dc403SDave Cobbley in_project_action = TableFilterActionToggle( 209eb8dc403SDave Cobbley "in_project", 210eb8dc403SDave Cobbley "Machines provided by layers added to this project", 211eb8dc403SDave Cobbley ProjectFilters.in_project(self.project_layers) 212eb8dc403SDave Cobbley ) 213eb8dc403SDave Cobbley 214eb8dc403SDave Cobbley not_in_project_action = TableFilterActionToggle( 215eb8dc403SDave Cobbley "not_in_project", 216eb8dc403SDave Cobbley "Machines provided by layers not added to this project", 217eb8dc403SDave Cobbley ProjectFilters.not_in_project(self.project_layers) 218eb8dc403SDave Cobbley ) 219eb8dc403SDave Cobbley 220eb8dc403SDave Cobbley in_current_project_filter.add_action(in_project_action) 221eb8dc403SDave Cobbley in_current_project_filter.add_action(not_in_project_action) 222eb8dc403SDave Cobbley self.add_filter(in_current_project_filter) 223eb8dc403SDave Cobbley 224eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 225eb8dc403SDave Cobbley prj = Project.objects.get(pk = kwargs['pid']) 226eb8dc403SDave Cobbley self.queryset = prj.get_all_compatible_machines() 227eb8dc403SDave Cobbley self.queryset = self.queryset.order_by(self.default_orderby) 228eb8dc403SDave Cobbley 229eb8dc403SDave Cobbley self.static_context_extra['current_layers'] = \ 230eb8dc403SDave Cobbley self.project_layers = \ 231eb8dc403SDave Cobbley prj.get_project_layer_versions(pk=True) 232eb8dc403SDave Cobbley 233eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 234eb8dc403SDave Cobbley 235eb8dc403SDave Cobbley self.add_column(title="Machine", 236eb8dc403SDave Cobbley hideable=False, 237eb8dc403SDave Cobbley orderable=True, 238eb8dc403SDave Cobbley field_name="name") 239eb8dc403SDave Cobbley 240eb8dc403SDave Cobbley self.add_column(title="Description", 241eb8dc403SDave Cobbley field_name="description") 242eb8dc403SDave Cobbley 243eb8dc403SDave Cobbley layer_link_template = ''' 244eb8dc403SDave Cobbley <a href="{% url 'layerdetails' extra.pid data.layer_version.id %}"> 245eb8dc403SDave Cobbley {{data.layer_version.layer.name}}</a> 246eb8dc403SDave Cobbley ''' 247eb8dc403SDave Cobbley 248eb8dc403SDave Cobbley self.add_column(title="Layer", 249eb8dc403SDave Cobbley static_data_name="layer_version__layer__name", 250eb8dc403SDave Cobbley static_data_template=layer_link_template, 251eb8dc403SDave Cobbley orderable=True) 252eb8dc403SDave Cobbley 253eb8dc403SDave Cobbley self.add_column(title="Git revision", 254eb8dc403SDave Cobbley help_text="The Git branch, tag or commit. For the layers from the OpenEmbedded layer source, the revision is always the branch compatible with the Yocto Project version you selected for this project", 255eb8dc403SDave Cobbley hidden=True, 256eb8dc403SDave Cobbley field_name="layer_version__get_vcs_reference") 257eb8dc403SDave Cobbley 258eb8dc403SDave Cobbley machine_file_template = '''<code>conf/machine/{{data.name}}.conf</code> 259eb8dc403SDave Cobbley <a href="{{data.get_vcs_machine_file_link_url}}" target="_blank"><span class="glyphicon glyphicon-new-window"></i></a>''' 260eb8dc403SDave Cobbley 261eb8dc403SDave Cobbley self.add_column(title="Machine file", 262eb8dc403SDave Cobbley hidden=True, 263eb8dc403SDave Cobbley static_data_name="machinefile", 264eb8dc403SDave Cobbley static_data_template=machine_file_template) 265eb8dc403SDave Cobbley 266eb8dc403SDave Cobbley self.add_column(title="Select", 267eb8dc403SDave Cobbley help_text="Sets the selected machine as the project machine. You can only have one machine per project", 268eb8dc403SDave Cobbley hideable=False, 269eb8dc403SDave Cobbley filter_name="in_current_project", 270eb8dc403SDave Cobbley static_data_name="add-del-layers", 271eb8dc403SDave Cobbley static_data_template='{% include "machine_btn.html" %}') 272eb8dc403SDave Cobbley 273eb8dc403SDave Cobbley 274eb8dc403SDave Cobbleyclass LayerMachinesTable(MachinesTable): 275eb8dc403SDave Cobbley """ Smaller version of the Machines table for use in layer details """ 276eb8dc403SDave Cobbley 277eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 278eb8dc403SDave Cobbley super(LayerMachinesTable, self).__init__(*args, **kwargs) 279eb8dc403SDave Cobbley 280eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 281eb8dc403SDave Cobbley context = super(LayerMachinesTable, self).get_context_data(**kwargs) 282eb8dc403SDave Cobbley context['layerversion'] = Layer_Version.objects.get(pk=kwargs['layerid']) 283eb8dc403SDave Cobbley return context 284eb8dc403SDave Cobbley 285eb8dc403SDave Cobbley 286eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 287eb8dc403SDave Cobbley MachinesTable.setup_queryset(self, *args, **kwargs) 288eb8dc403SDave Cobbley 289eb8dc403SDave Cobbley self.queryset = self.queryset.filter(layer_version__pk=int(kwargs['layerid'])) 290eb8dc403SDave Cobbley self.queryset = self.queryset.order_by(self.default_orderby) 291eb8dc403SDave Cobbley self.static_context_extra['in_prj'] = ProjectLayer.objects.filter(Q(project=kwargs['pid']) & Q(layercommit=kwargs['layerid'])).count() 292eb8dc403SDave Cobbley 293eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 294eb8dc403SDave Cobbley self.add_column(title="Machine", 295eb8dc403SDave Cobbley hideable=False, 296eb8dc403SDave Cobbley orderable=True, 297eb8dc403SDave Cobbley field_name="name") 298eb8dc403SDave Cobbley 299eb8dc403SDave Cobbley self.add_column(title="Description", 300eb8dc403SDave Cobbley field_name="description") 301eb8dc403SDave Cobbley 302eb8dc403SDave Cobbley select_btn_template = ''' 303eb8dc403SDave Cobbley <a href="{% url "project" extra.pid %}?setMachine={{data.name}}" 304eb8dc403SDave Cobbley class="btn btn-default btn-block select-machine-btn 305eb8dc403SDave Cobbley {% if extra.in_prj == 0%}disabled{%endif%}">Select machine</a> 306eb8dc403SDave Cobbley ''' 307eb8dc403SDave Cobbley 308eb8dc403SDave Cobbley self.add_column(title="Select machine", 309eb8dc403SDave Cobbley static_data_name="add-del-layers", 310eb8dc403SDave Cobbley static_data_template=select_btn_template) 311eb8dc403SDave Cobbley 312eb8dc403SDave Cobbley 313eb8dc403SDave Cobbleyclass RecipesTable(ToasterTable): 314eb8dc403SDave Cobbley """Table of All Recipes in Toaster""" 315eb8dc403SDave Cobbley 316eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 317eb8dc403SDave Cobbley super(RecipesTable, self).__init__(*args, **kwargs) 318eb8dc403SDave Cobbley self.empty_state = "Toaster has no recipe information. To generate recipe information you need to run a build." 319eb8dc403SDave Cobbley 320eb8dc403SDave Cobbley build_col = { 'title' : "Build", 321eb8dc403SDave Cobbley 'help_text' : "Before building a recipe, you might need to add the corresponding layer to your project", 322eb8dc403SDave Cobbley 'hideable' : False, 323eb8dc403SDave Cobbley 'filter_name' : "in_current_project", 324eb8dc403SDave Cobbley 'static_data_name' : "add-del-layers", 325eb8dc403SDave Cobbley 'static_data_template' : '{% include "recipe_btn.html" %}'} 3261a4b7ee2SBrad Bishop if '1' == os.environ.get('TOASTER_PROJECTSPECIFIC'): 3271a4b7ee2SBrad Bishop build_col['static_data_template'] = '{% include "recipe_add_btn.html" %}' 328eb8dc403SDave Cobbley 329eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 330eb8dc403SDave Cobbley project = Project.objects.get(pk=kwargs['pid']) 331eb8dc403SDave Cobbley context = super(RecipesTable, self).get_context_data(**kwargs) 332eb8dc403SDave Cobbley 333eb8dc403SDave Cobbley context['project'] = project 334eb8dc403SDave Cobbley context['projectlayers'] = [player.layercommit.id for player in ProjectLayer.objects.filter(project=context['project'])] 335eb8dc403SDave Cobbley 336eb8dc403SDave Cobbley return context 337eb8dc403SDave Cobbley 338eb8dc403SDave Cobbley def setup_filters(self, *args, **kwargs): 339eb8dc403SDave Cobbley table_filter = TableFilter( 340eb8dc403SDave Cobbley 'in_current_project', 341eb8dc403SDave Cobbley 'Filter by project recipes' 342eb8dc403SDave Cobbley ) 343eb8dc403SDave Cobbley 344eb8dc403SDave Cobbley in_project_action = TableFilterActionToggle( 345eb8dc403SDave Cobbley 'in_project', 346eb8dc403SDave Cobbley 'Recipes provided by layers added to this project', 347eb8dc403SDave Cobbley ProjectFilters.in_project(self.project_layers) 348eb8dc403SDave Cobbley ) 349eb8dc403SDave Cobbley 350eb8dc403SDave Cobbley not_in_project_action = TableFilterActionToggle( 351eb8dc403SDave Cobbley 'not_in_project', 352eb8dc403SDave Cobbley 'Recipes provided by layers not added to this project', 353eb8dc403SDave Cobbley ProjectFilters.not_in_project(self.project_layers) 354eb8dc403SDave Cobbley ) 355eb8dc403SDave Cobbley 356eb8dc403SDave Cobbley table_filter.add_action(in_project_action) 357eb8dc403SDave Cobbley table_filter.add_action(not_in_project_action) 358eb8dc403SDave Cobbley self.add_filter(table_filter) 359eb8dc403SDave Cobbley 360eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 361eb8dc403SDave Cobbley prj = Project.objects.get(pk = kwargs['pid']) 362eb8dc403SDave Cobbley 363eb8dc403SDave Cobbley # Project layers used by the filters 364eb8dc403SDave Cobbley self.project_layers = prj.get_project_layer_versions(pk=True) 365eb8dc403SDave Cobbley 366eb8dc403SDave Cobbley # Project layers used to switch the button states 367eb8dc403SDave Cobbley self.static_context_extra['current_layers'] = self.project_layers 368eb8dc403SDave Cobbley 369eb8dc403SDave Cobbley self.queryset = prj.get_all_compatible_recipes() 370eb8dc403SDave Cobbley 371eb8dc403SDave Cobbley 372eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 373eb8dc403SDave Cobbley 374eb8dc403SDave Cobbley self.add_column(title="Version", 375eb8dc403SDave Cobbley hidden=False, 376eb8dc403SDave Cobbley field_name="version") 377eb8dc403SDave Cobbley 378eb8dc403SDave Cobbley self.add_column(title="Description", 379eb8dc403SDave Cobbley field_name="get_description_or_summary") 380eb8dc403SDave Cobbley 381eb8dc403SDave Cobbley recipe_file_template = ''' 382eb8dc403SDave Cobbley <code>{{data.file_path}}</code> 383eb8dc403SDave Cobbley <a href="{{data.get_vcs_recipe_file_link_url}}" target="_blank"> 384eb8dc403SDave Cobbley <span class="glyphicon glyphicon-new-window"></i> 385eb8dc403SDave Cobbley </a> 386eb8dc403SDave Cobbley ''' 387eb8dc403SDave Cobbley 388eb8dc403SDave Cobbley self.add_column(title="Recipe file", 389eb8dc403SDave Cobbley help_text="Path to the recipe .bb file", 390eb8dc403SDave Cobbley hidden=True, 391eb8dc403SDave Cobbley static_data_name="recipe-file", 392eb8dc403SDave Cobbley static_data_template=recipe_file_template) 393eb8dc403SDave Cobbley 394eb8dc403SDave Cobbley self.add_column(title="Section", 395eb8dc403SDave Cobbley help_text="The section in which recipes should be categorized", 396eb8dc403SDave Cobbley hidden=True, 397eb8dc403SDave Cobbley orderable=True, 398eb8dc403SDave Cobbley field_name="section") 399eb8dc403SDave Cobbley 400eb8dc403SDave Cobbley layer_link_template = ''' 401eb8dc403SDave Cobbley <a href="{% url 'layerdetails' extra.pid data.layer_version.id %}"> 402eb8dc403SDave Cobbley {{data.layer_version.layer.name}}</a> 403eb8dc403SDave Cobbley ''' 404eb8dc403SDave Cobbley 405eb8dc403SDave Cobbley self.add_column(title="Layer", 406eb8dc403SDave Cobbley help_text="The name of the layer providing the recipe", 407eb8dc403SDave Cobbley orderable=True, 408eb8dc403SDave Cobbley static_data_name="layer_version__layer__name", 409eb8dc403SDave Cobbley static_data_template=layer_link_template) 410eb8dc403SDave Cobbley 411eb8dc403SDave Cobbley self.add_column(title="License", 412eb8dc403SDave Cobbley help_text="The list of source licenses for the recipe. Multiple license names separated by the pipe character indicates a choice between licenses. Multiple license names separated by the ampersand character indicates multiple licenses exist that cover different parts of the source", 413eb8dc403SDave Cobbley hidden=True, 414eb8dc403SDave Cobbley orderable=True, 415eb8dc403SDave Cobbley field_name="license") 416eb8dc403SDave Cobbley 417eb8dc403SDave Cobbley revision_link_template = ''' 418eb8dc403SDave Cobbley {% if data.layer_version.layer.local_source_dir %} 419eb8dc403SDave Cobbley <span class="text-muted">Not applicable</span> 420eb8dc403SDave Cobbley <span class="glyphicon glyphicon-question-sign get-help" data-original-title="" title="The source code of {{data.layer_version.layer.name}} is not in a Git repository, so there is no revision associated with it"> </span> 421eb8dc403SDave Cobbley {% else %} 422eb8dc403SDave Cobbley {{data.layer_version.get_vcs_reference}} 423eb8dc403SDave Cobbley {% endif %} 424eb8dc403SDave Cobbley ''' 425eb8dc403SDave Cobbley 426eb8dc403SDave Cobbley self.add_column(title="Git revision", 427eb8dc403SDave Cobbley hidden=True, 428eb8dc403SDave Cobbley static_data_name="layer_version__get_vcs_reference", 429eb8dc403SDave Cobbley static_data_template=revision_link_template) 430eb8dc403SDave Cobbley 431eb8dc403SDave Cobbley 432eb8dc403SDave Cobbleyclass LayerRecipesTable(RecipesTable): 433eb8dc403SDave Cobbley """ Smaller version of the Recipes table for use in layer details """ 434eb8dc403SDave Cobbley 435eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 436eb8dc403SDave Cobbley super(LayerRecipesTable, self).__init__(*args, **kwargs) 437eb8dc403SDave Cobbley self.default_orderby = "name" 438eb8dc403SDave Cobbley 439eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 440eb8dc403SDave Cobbley context = super(LayerRecipesTable, self).get_context_data(**kwargs) 441eb8dc403SDave Cobbley context['layerversion'] = Layer_Version.objects.get(pk=kwargs['layerid']) 442eb8dc403SDave Cobbley return context 443eb8dc403SDave Cobbley 444eb8dc403SDave Cobbley 445eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 446eb8dc403SDave Cobbley self.queryset = \ 447eb8dc403SDave Cobbley Recipe.objects.filter(layer_version__pk=int(kwargs['layerid'])) 448eb8dc403SDave Cobbley 449eb8dc403SDave Cobbley self.queryset = self.queryset.order_by(self.default_orderby) 450eb8dc403SDave Cobbley self.static_context_extra['in_prj'] = ProjectLayer.objects.filter(Q(project=kwargs['pid']) & Q(layercommit=kwargs['layerid'])).count() 451eb8dc403SDave Cobbley 452eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 453eb8dc403SDave Cobbley self.add_column(title="Recipe", 454eb8dc403SDave Cobbley help_text="Information about a single piece of software, including where to download the source, configuration options, how to compile the source files and how to package the compiled output", 455eb8dc403SDave Cobbley hideable=False, 456eb8dc403SDave Cobbley orderable=True, 457eb8dc403SDave Cobbley field_name="name") 458eb8dc403SDave Cobbley 459eb8dc403SDave Cobbley self.add_column(title="Version", 460eb8dc403SDave Cobbley field_name="version") 461eb8dc403SDave Cobbley 462eb8dc403SDave Cobbley self.add_column(title="Description", 463eb8dc403SDave Cobbley field_name="get_description_or_summary") 464eb8dc403SDave Cobbley 465eb8dc403SDave Cobbley build_recipe_template = ''' 466eb8dc403SDave Cobbley <a class="btn btn-default btn-block build-recipe-btn 467eb8dc403SDave Cobbley {% if extra.in_prj == 0 %}disabled{% endif %}" 468eb8dc403SDave Cobbley data-recipe-name="{{data.name}}">Build recipe</a> 469eb8dc403SDave Cobbley ''' 470eb8dc403SDave Cobbley 471eb8dc403SDave Cobbley self.add_column(title="Build recipe", 472eb8dc403SDave Cobbley static_data_name="add-del-layers", 473eb8dc403SDave Cobbley static_data_template=build_recipe_template) 474eb8dc403SDave Cobbley 475eb8dc403SDave Cobbleyclass CustomImagesTable(ToasterTable): 476eb8dc403SDave Cobbley """ Table to display your custom images """ 477eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 478eb8dc403SDave Cobbley super(CustomImagesTable, self).__init__(*args, **kwargs) 479eb8dc403SDave Cobbley self.title = "Custom images" 480eb8dc403SDave Cobbley self.default_orderby = "name" 481eb8dc403SDave Cobbley 482eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 483eb8dc403SDave Cobbley context = super(CustomImagesTable, self).get_context_data(**kwargs) 484eb8dc403SDave Cobbley 485eb8dc403SDave Cobbley empty_state_template = ''' 486eb8dc403SDave Cobbley You have not created any custom images yet. 487eb8dc403SDave Cobbley <a href="{% url 'newcustomimage' data.pid %}"> 488eb8dc403SDave Cobbley Create your first custom image</a> 489eb8dc403SDave Cobbley ''' 490eb8dc403SDave Cobbley context['empty_state'] = self.render_static_data(empty_state_template, 491eb8dc403SDave Cobbley kwargs) 492eb8dc403SDave Cobbley project = Project.objects.get(pk=kwargs['pid']) 493eb8dc403SDave Cobbley 494eb8dc403SDave Cobbley # TODO put project into the ToasterTable base class 495eb8dc403SDave Cobbley context['project'] = project 496eb8dc403SDave Cobbley return context 497eb8dc403SDave Cobbley 498eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 499eb8dc403SDave Cobbley prj = Project.objects.get(pk = kwargs['pid']) 500eb8dc403SDave Cobbley self.queryset = CustomImageRecipe.objects.filter(project=prj) 501eb8dc403SDave Cobbley self.queryset = self.queryset.order_by(self.default_orderby) 502eb8dc403SDave Cobbley 503eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 504eb8dc403SDave Cobbley 505eb8dc403SDave Cobbley name_link_template = ''' 506eb8dc403SDave Cobbley <a href="{% url 'customrecipe' extra.pid data.id %}"> 507eb8dc403SDave Cobbley {{data.name}} 508eb8dc403SDave Cobbley </a> 509eb8dc403SDave Cobbley ''' 510eb8dc403SDave Cobbley 511eb8dc403SDave Cobbley self.add_column(title="Custom image", 512eb8dc403SDave Cobbley hideable=False, 513eb8dc403SDave Cobbley orderable=True, 514eb8dc403SDave Cobbley field_name="name", 515eb8dc403SDave Cobbley static_data_name="name", 516eb8dc403SDave Cobbley static_data_template=name_link_template) 517eb8dc403SDave Cobbley 518eb8dc403SDave Cobbley recipe_file_template = ''' 519eb8dc403SDave Cobbley {% if data.get_base_recipe_file %} 520eb8dc403SDave Cobbley <code>{{data.name}}_{{data.version}}.bb</code> 521eb8dc403SDave Cobbley <a href="{% url 'customrecipedownload' extra.pid data.pk %}" 522eb8dc403SDave Cobbley class="glyphicon glyphicon-download-alt get-help" title="Download recipe file"></a> 523eb8dc403SDave Cobbley {% endif %}''' 524eb8dc403SDave Cobbley 525eb8dc403SDave Cobbley self.add_column(title="Recipe file", 526eb8dc403SDave Cobbley static_data_name='recipe_file_download', 527eb8dc403SDave Cobbley static_data_template=recipe_file_template) 528eb8dc403SDave Cobbley 529eb8dc403SDave Cobbley approx_packages_template = ''' 530eb8dc403SDave Cobbley {% if data.get_all_packages.count > 0 %} 531eb8dc403SDave Cobbley <a href="{% url 'customrecipe' extra.pid data.id %}"> 532eb8dc403SDave Cobbley {{data.get_all_packages.count}} 533eb8dc403SDave Cobbley </a> 534eb8dc403SDave Cobbley {% endif %}''' 535eb8dc403SDave Cobbley 536eb8dc403SDave Cobbley self.add_column(title="Packages", 537eb8dc403SDave Cobbley static_data_name='approx_packages', 538eb8dc403SDave Cobbley static_data_template=approx_packages_template) 539eb8dc403SDave Cobbley 540eb8dc403SDave Cobbley 541eb8dc403SDave Cobbley build_btn_template = ''' 542eb8dc403SDave Cobbley <button data-recipe-name="{{data.name}}" 543eb8dc403SDave Cobbley class="btn btn-default btn-block build-recipe-btn"> 544eb8dc403SDave Cobbley Build 545eb8dc403SDave Cobbley </button>''' 546eb8dc403SDave Cobbley 547eb8dc403SDave Cobbley self.add_column(title="Build", 548eb8dc403SDave Cobbley hideable=False, 549eb8dc403SDave Cobbley static_data_name='build_custom_img', 550eb8dc403SDave Cobbley static_data_template=build_btn_template) 551eb8dc403SDave Cobbley 552eb8dc403SDave Cobbleyclass ImageRecipesTable(RecipesTable): 553eb8dc403SDave Cobbley """ A subset of the recipes table which displayed just image recipes """ 554eb8dc403SDave Cobbley 555eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 556eb8dc403SDave Cobbley super(ImageRecipesTable, self).__init__(*args, **kwargs) 557eb8dc403SDave Cobbley self.title = "Compatible image recipes" 558eb8dc403SDave Cobbley self.default_orderby = "name" 559eb8dc403SDave Cobbley 560eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 561eb8dc403SDave Cobbley super(ImageRecipesTable, self).setup_queryset(*args, **kwargs) 562eb8dc403SDave Cobbley 563eb8dc403SDave Cobbley custom_image_recipes = CustomImageRecipe.objects.filter( 564eb8dc403SDave Cobbley project=kwargs['pid']) 565eb8dc403SDave Cobbley self.queryset = self.queryset.filter( 566eb8dc403SDave Cobbley Q(is_image=True) & ~Q(pk__in=custom_image_recipes)) 567eb8dc403SDave Cobbley self.queryset = self.queryset.order_by(self.default_orderby) 568eb8dc403SDave Cobbley 569eb8dc403SDave Cobbley 570eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 571eb8dc403SDave Cobbley 572eb8dc403SDave Cobbley name_link_template = ''' 573eb8dc403SDave Cobbley <a href="{% url 'recipedetails' extra.pid data.pk %}">{{data.name}}</a> 574eb8dc403SDave Cobbley ''' 575eb8dc403SDave Cobbley 576eb8dc403SDave Cobbley self.add_column(title="Image recipe", 577eb8dc403SDave Cobbley help_text="When you build an image recipe, you get an " 578eb8dc403SDave Cobbley "image: a root file system you can" 579eb8dc403SDave Cobbley "deploy to a machine", 580eb8dc403SDave Cobbley hideable=False, 581eb8dc403SDave Cobbley orderable=True, 582eb8dc403SDave Cobbley static_data_name="name", 583eb8dc403SDave Cobbley static_data_template=name_link_template, 584eb8dc403SDave Cobbley field_name="name") 585eb8dc403SDave Cobbley 586eb8dc403SDave Cobbley super(ImageRecipesTable, self).setup_columns(*args, **kwargs) 587eb8dc403SDave Cobbley 588eb8dc403SDave Cobbley self.add_column(**RecipesTable.build_col) 589eb8dc403SDave Cobbley 590eb8dc403SDave Cobbley 591eb8dc403SDave Cobbleyclass NewCustomImagesTable(ImageRecipesTable): 592eb8dc403SDave Cobbley """ Table which displays Images recipes which can be customised """ 593eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 594eb8dc403SDave Cobbley super(NewCustomImagesTable, self).__init__(*args, **kwargs) 595eb8dc403SDave Cobbley self.title = "Select the image recipe you want to customise" 596eb8dc403SDave Cobbley 597eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 598eb8dc403SDave Cobbley super(ImageRecipesTable, self).setup_queryset(*args, **kwargs) 599eb8dc403SDave Cobbley prj = Project.objects.get(pk = kwargs['pid']) 600eb8dc403SDave Cobbley self.static_context_extra['current_layers'] = \ 601eb8dc403SDave Cobbley prj.get_project_layer_versions(pk=True) 602eb8dc403SDave Cobbley 603eb8dc403SDave Cobbley self.queryset = self.queryset.filter(is_image=True) 604eb8dc403SDave Cobbley 605eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 606eb8dc403SDave Cobbley 607eb8dc403SDave Cobbley name_link_template = ''' 608eb8dc403SDave Cobbley <a href="{% url 'recipedetails' extra.pid data.pk %}">{{data.name}}</a> 609eb8dc403SDave Cobbley ''' 610eb8dc403SDave Cobbley 611eb8dc403SDave Cobbley self.add_column(title="Image recipe", 612eb8dc403SDave Cobbley help_text="When you build an image recipe, you get an " 613eb8dc403SDave Cobbley "image: a root file system you can" 614eb8dc403SDave Cobbley "deploy to a machine", 615eb8dc403SDave Cobbley hideable=False, 616eb8dc403SDave Cobbley orderable=True, 617eb8dc403SDave Cobbley static_data_name="name", 618eb8dc403SDave Cobbley static_data_template=name_link_template, 619eb8dc403SDave Cobbley field_name="name") 620eb8dc403SDave Cobbley 621eb8dc403SDave Cobbley super(ImageRecipesTable, self).setup_columns(*args, **kwargs) 622eb8dc403SDave Cobbley 623eb8dc403SDave Cobbley self.add_column(title="Customise", 624eb8dc403SDave Cobbley hideable=False, 625eb8dc403SDave Cobbley filter_name="in_current_project", 626eb8dc403SDave Cobbley static_data_name="customise-or-add-recipe", 627eb8dc403SDave Cobbley static_data_template='{% include "customise_btn.html" %}') 628eb8dc403SDave Cobbley 629eb8dc403SDave Cobbley 630eb8dc403SDave Cobbleyclass SoftwareRecipesTable(RecipesTable): 631eb8dc403SDave Cobbley """ Displays just the software recipes """ 632eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 633eb8dc403SDave Cobbley super(SoftwareRecipesTable, self).__init__(*args, **kwargs) 634eb8dc403SDave Cobbley self.title = "Compatible software recipes" 635eb8dc403SDave Cobbley self.default_orderby = "name" 636eb8dc403SDave Cobbley 637eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 638eb8dc403SDave Cobbley super(SoftwareRecipesTable, self).setup_queryset(*args, **kwargs) 639eb8dc403SDave Cobbley 640eb8dc403SDave Cobbley self.queryset = self.queryset.filter(is_image=False) 641eb8dc403SDave Cobbley self.queryset = self.queryset.order_by(self.default_orderby) 642eb8dc403SDave Cobbley 643eb8dc403SDave Cobbley 644eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 645eb8dc403SDave Cobbley self.add_column(title="Software recipe", 646eb8dc403SDave Cobbley help_text="Information about a single piece of " 647eb8dc403SDave Cobbley "software, including where to download the source, " 648eb8dc403SDave Cobbley "configuration options, how to compile the source " 649eb8dc403SDave Cobbley "files and how to package the compiled output", 650eb8dc403SDave Cobbley hideable=False, 651eb8dc403SDave Cobbley orderable=True, 652eb8dc403SDave Cobbley field_name="name") 653eb8dc403SDave Cobbley 654eb8dc403SDave Cobbley super(SoftwareRecipesTable, self).setup_columns(*args, **kwargs) 655eb8dc403SDave Cobbley 656eb8dc403SDave Cobbley self.add_column(**RecipesTable.build_col) 657eb8dc403SDave Cobbley 658eb8dc403SDave Cobbleyclass PackagesTable(ToasterTable): 659eb8dc403SDave Cobbley """ Table to display the packages in a recipe from it's last successful 660eb8dc403SDave Cobbley build""" 661eb8dc403SDave Cobbley 662eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 663eb8dc403SDave Cobbley super(PackagesTable, self).__init__(*args, **kwargs) 664eb8dc403SDave Cobbley self.title = "Packages included" 665eb8dc403SDave Cobbley self.packages = None 666eb8dc403SDave Cobbley self.default_orderby = "name" 667eb8dc403SDave Cobbley 668eb8dc403SDave Cobbley def create_package_list(self, recipe, project_id): 669eb8dc403SDave Cobbley """Creates a list of packages for the specified recipe by looking for 670eb8dc403SDave Cobbley the last SUCCEEDED build of ther recipe""" 671eb8dc403SDave Cobbley 672eb8dc403SDave Cobbley target = Target.objects.filter(Q(target=recipe.name) & 673eb8dc403SDave Cobbley Q(build__project_id=project_id) & 674eb8dc403SDave Cobbley Q(build__outcome=Build.SUCCEEDED) 675eb8dc403SDave Cobbley ).last() 676eb8dc403SDave Cobbley 677eb8dc403SDave Cobbley if target: 678eb8dc403SDave Cobbley pkgs = target.target_installed_package_set.values_list('package', 679eb8dc403SDave Cobbley flat=True) 680eb8dc403SDave Cobbley return Package.objects.filter(pk__in=pkgs) 681eb8dc403SDave Cobbley 682eb8dc403SDave Cobbley # Target/recipe never successfully built so empty queryset 683eb8dc403SDave Cobbley return Package.objects.none() 684eb8dc403SDave Cobbley 685eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 686eb8dc403SDave Cobbley """Context for rendering the sidebar and other items on the recipe 687eb8dc403SDave Cobbley details page """ 688eb8dc403SDave Cobbley context = super(PackagesTable, self).get_context_data(**kwargs) 689eb8dc403SDave Cobbley 690eb8dc403SDave Cobbley recipe = Recipe.objects.get(pk=kwargs['recipe_id']) 691eb8dc403SDave Cobbley project = Project.objects.get(pk=kwargs['pid']) 692eb8dc403SDave Cobbley 693eb8dc403SDave Cobbley in_project = (recipe.layer_version.pk in 694eb8dc403SDave Cobbley project.get_project_layer_versions(pk=True)) 695eb8dc403SDave Cobbley 696eb8dc403SDave Cobbley packages = self.create_package_list(recipe, project.pk) 697eb8dc403SDave Cobbley 698eb8dc403SDave Cobbley context.update({'project': project, 699eb8dc403SDave Cobbley 'recipe' : recipe, 700eb8dc403SDave Cobbley 'packages': packages, 701eb8dc403SDave Cobbley 'approx_pkg_size' : packages.aggregate(Sum('size')), 702eb8dc403SDave Cobbley 'in_project' : in_project, 703eb8dc403SDave Cobbley }) 704eb8dc403SDave Cobbley 705eb8dc403SDave Cobbley return context 706eb8dc403SDave Cobbley 707eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 708eb8dc403SDave Cobbley recipe = Recipe.objects.get(pk=kwargs['recipe_id']) 709eb8dc403SDave Cobbley self.static_context_extra['target_name'] = recipe.name 710eb8dc403SDave Cobbley 711eb8dc403SDave Cobbley self.queryset = self.create_package_list(recipe, kwargs['pid']) 712eb8dc403SDave Cobbley self.queryset = self.queryset.order_by('name') 713eb8dc403SDave Cobbley 714eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 715eb8dc403SDave Cobbley self.add_column(title="Package", 716eb8dc403SDave Cobbley hideable=False, 717eb8dc403SDave Cobbley orderable=True, 718eb8dc403SDave Cobbley field_name="name") 719eb8dc403SDave Cobbley 720eb8dc403SDave Cobbley self.add_column(title="Package Version", 721eb8dc403SDave Cobbley field_name="version", 722eb8dc403SDave Cobbley hideable=False) 723eb8dc403SDave Cobbley 724eb8dc403SDave Cobbley self.add_column(title="Approx Size", 725eb8dc403SDave Cobbley orderable=True, 726eb8dc403SDave Cobbley field_name="size", 727eb8dc403SDave Cobbley static_data_name="size", 728eb8dc403SDave Cobbley static_data_template="{% load projecttags %} \ 729eb8dc403SDave Cobbley {{data.size|filtered_filesizeformat}}") 730eb8dc403SDave Cobbley 731eb8dc403SDave Cobbley self.add_column(title="License", 732eb8dc403SDave Cobbley field_name="license", 733eb8dc403SDave Cobbley orderable=True, 734eb8dc403SDave Cobbley hidden=True) 735eb8dc403SDave Cobbley 736eb8dc403SDave Cobbley 737eb8dc403SDave Cobbley self.add_column(title="Dependencies", 738eb8dc403SDave Cobbley static_data_name="dependencies", 739eb8dc403SDave Cobbley static_data_template='\ 740eb8dc403SDave Cobbley {% include "snippets/pkg_dependencies_popover.html" %}') 741eb8dc403SDave Cobbley 742eb8dc403SDave Cobbley self.add_column(title="Reverse dependencies", 743eb8dc403SDave Cobbley static_data_name="reverse_dependencies", 744eb8dc403SDave Cobbley static_data_template='\ 745eb8dc403SDave Cobbley {% include "snippets/pkg_revdependencies_popover.html" %}', 746eb8dc403SDave Cobbley hidden=True) 747eb8dc403SDave Cobbley 748eb8dc403SDave Cobbley self.add_column(title="Recipe", 749eb8dc403SDave Cobbley field_name="recipe__name", 750eb8dc403SDave Cobbley orderable=True, 751eb8dc403SDave Cobbley hidden=True) 752eb8dc403SDave Cobbley 753eb8dc403SDave Cobbley self.add_column(title="Recipe version", 754eb8dc403SDave Cobbley field_name="recipe__version", 755eb8dc403SDave Cobbley hidden=True) 756eb8dc403SDave Cobbley 757eb8dc403SDave Cobbley 758eb8dc403SDave Cobbleyclass SelectPackagesTable(PackagesTable): 759eb8dc403SDave Cobbley """ Table to display the packages to add and remove from an image """ 760eb8dc403SDave Cobbley 761eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 762eb8dc403SDave Cobbley super(SelectPackagesTable, self).__init__(*args, **kwargs) 763eb8dc403SDave Cobbley self.title = "Add | Remove packages" 764eb8dc403SDave Cobbley 765eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 766eb8dc403SDave Cobbley self.cust_recipe =\ 767eb8dc403SDave Cobbley CustomImageRecipe.objects.get(pk=kwargs['custrecipeid']) 768eb8dc403SDave Cobbley prj = Project.objects.get(pk = kwargs['pid']) 769eb8dc403SDave Cobbley 770eb8dc403SDave Cobbley current_packages = self.cust_recipe.get_all_packages() 771eb8dc403SDave Cobbley 772eb8dc403SDave Cobbley current_recipes = prj.get_available_recipes() 773eb8dc403SDave Cobbley 774eb8dc403SDave Cobbley # only show packages where recipes->layers are in the project 775eb8dc403SDave Cobbley self.queryset = CustomImagePackage.objects.filter( 776eb8dc403SDave Cobbley ~Q(recipe=None) & 777eb8dc403SDave Cobbley Q(recipe__in=current_recipes)) 778eb8dc403SDave Cobbley 779eb8dc403SDave Cobbley self.queryset = self.queryset.order_by('name') 780eb8dc403SDave Cobbley 781eb8dc403SDave Cobbley # This target is the target used to work out which group of dependences 782eb8dc403SDave Cobbley # to display, if we've built the custom image we use it otherwise we 783eb8dc403SDave Cobbley # can use the based recipe instead 784eb8dc403SDave Cobbley if prj.build_set.filter(target__target=self.cust_recipe.name).count()\ 785eb8dc403SDave Cobbley > 0: 786eb8dc403SDave Cobbley self.static_context_extra['target_name'] = self.cust_recipe.name 787eb8dc403SDave Cobbley else: 788eb8dc403SDave Cobbley self.static_context_extra['target_name'] =\ 789eb8dc403SDave Cobbley Package_DependencyManager.TARGET_LATEST 790eb8dc403SDave Cobbley 791eb8dc403SDave Cobbley self.static_context_extra['recipe_id'] = kwargs['custrecipeid'] 792eb8dc403SDave Cobbley 793eb8dc403SDave Cobbley 794eb8dc403SDave Cobbley self.static_context_extra['current_packages'] = \ 795eb8dc403SDave Cobbley current_packages.values_list('pk', flat=True) 796eb8dc403SDave Cobbley 797eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 798eb8dc403SDave Cobbley # to reuse the Super class map the custrecipeid to the recipe_id 799eb8dc403SDave Cobbley kwargs['recipe_id'] = kwargs['custrecipeid'] 800eb8dc403SDave Cobbley context = super(SelectPackagesTable, self).get_context_data(**kwargs) 801eb8dc403SDave Cobbley custom_recipe = \ 802eb8dc403SDave Cobbley CustomImageRecipe.objects.get(pk=kwargs['custrecipeid']) 803eb8dc403SDave Cobbley 804eb8dc403SDave Cobbley context['recipe'] = custom_recipe 805eb8dc403SDave Cobbley context['approx_pkg_size'] = \ 806eb8dc403SDave Cobbley custom_recipe.get_all_packages().aggregate(Sum('size')) 807eb8dc403SDave Cobbley return context 808eb8dc403SDave Cobbley 809eb8dc403SDave Cobbley 810eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 811eb8dc403SDave Cobbley super(SelectPackagesTable, self).setup_columns(*args, **kwargs) 812eb8dc403SDave Cobbley 813eb8dc403SDave Cobbley add_remove_template = '{% include "pkg_add_rm_btn.html" %}' 814eb8dc403SDave Cobbley 815eb8dc403SDave Cobbley self.add_column(title="Add | Remove", 816eb8dc403SDave Cobbley hideable=False, 817eb8dc403SDave Cobbley help_text="Use the add and remove buttons to modify " 818eb8dc403SDave Cobbley "the package content of your custom image", 819eb8dc403SDave Cobbley static_data_name="add_rm_pkg_btn", 820eb8dc403SDave Cobbley static_data_template=add_remove_template, 821eb8dc403SDave Cobbley filter_name='in_current_image_filter') 822eb8dc403SDave Cobbley 823eb8dc403SDave Cobbley def setup_filters(self, *args, **kwargs): 824eb8dc403SDave Cobbley in_current_image_filter = TableFilter( 825eb8dc403SDave Cobbley 'in_current_image_filter', 826eb8dc403SDave Cobbley 'Filter by added packages' 827eb8dc403SDave Cobbley ) 828eb8dc403SDave Cobbley 829eb8dc403SDave Cobbley in_image_action = TableFilterActionToggle( 830eb8dc403SDave Cobbley 'in_image', 831eb8dc403SDave Cobbley 'Packages in %s' % self.cust_recipe.name, 832eb8dc403SDave Cobbley Q(pk__in=self.static_context_extra['current_packages']) 833eb8dc403SDave Cobbley ) 834eb8dc403SDave Cobbley 835eb8dc403SDave Cobbley not_in_image_action = TableFilterActionToggle( 836eb8dc403SDave Cobbley 'not_in_image', 837eb8dc403SDave Cobbley 'Packages not added to %s' % self.cust_recipe.name, 838eb8dc403SDave Cobbley ~Q(pk__in=self.static_context_extra['current_packages']) 839eb8dc403SDave Cobbley ) 840eb8dc403SDave Cobbley 841eb8dc403SDave Cobbley in_current_image_filter.add_action(in_image_action) 842eb8dc403SDave Cobbley in_current_image_filter.add_action(not_in_image_action) 843eb8dc403SDave Cobbley self.add_filter(in_current_image_filter) 844eb8dc403SDave Cobbley 845eb8dc403SDave Cobbleyclass ProjectsTable(ToasterTable): 846eb8dc403SDave Cobbley """Table of projects in Toaster""" 847eb8dc403SDave Cobbley 848eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 849eb8dc403SDave Cobbley super(ProjectsTable, self).__init__(*args, **kwargs) 850eb8dc403SDave Cobbley self.default_orderby = '-updated' 851eb8dc403SDave Cobbley self.title = 'All projects' 852eb8dc403SDave Cobbley self.static_context_extra['Build'] = Build 853eb8dc403SDave Cobbley 854eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 855eb8dc403SDave Cobbley return super(ProjectsTable, self).get_context_data(**kwargs) 856eb8dc403SDave Cobbley 857eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 858eb8dc403SDave Cobbley queryset = Project.objects.all() 859eb8dc403SDave Cobbley 860eb8dc403SDave Cobbley # annotate each project with its number of builds 861eb8dc403SDave Cobbley queryset = queryset.annotate(num_builds=Count('build')) 862eb8dc403SDave Cobbley 863eb8dc403SDave Cobbley # exclude the command line builds project if it has no builds 864eb8dc403SDave Cobbley q_default_with_builds = Q(is_default=True) & Q(num_builds__gt=0) 865eb8dc403SDave Cobbley queryset = queryset.filter(Q(is_default=False) | 866eb8dc403SDave Cobbley q_default_with_builds) 867eb8dc403SDave Cobbley 868eb8dc403SDave Cobbley # order rows 869eb8dc403SDave Cobbley queryset = queryset.order_by(self.default_orderby) 870eb8dc403SDave Cobbley 871eb8dc403SDave Cobbley self.queryset = queryset 872eb8dc403SDave Cobbley 873eb8dc403SDave Cobbley # columns: last activity on (updated) - DEFAULT, project (name), release, 874eb8dc403SDave Cobbley # machine, number of builds, last build outcome, recipe (name), errors, 875eb8dc403SDave Cobbley # warnings, image files 876eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 877eb8dc403SDave Cobbley name_template = ''' 878eb8dc403SDave Cobbley {% load project_url_tag %} 879eb8dc403SDave Cobbley <span data-project-field="name"> 880eb8dc403SDave Cobbley <a href="{% project_url data %}"> 881eb8dc403SDave Cobbley {{data.name}} 882eb8dc403SDave Cobbley </a> 883eb8dc403SDave Cobbley </span> 884eb8dc403SDave Cobbley ''' 885eb8dc403SDave Cobbley 886eb8dc403SDave Cobbley last_activity_on_template = ''' 887eb8dc403SDave Cobbley {% load project_url_tag %} 888eb8dc403SDave Cobbley <span data-project-field="updated"> 889eb8dc403SDave Cobbley {{data.updated | date:"d/m/y H:i"}} 890eb8dc403SDave Cobbley </span> 891eb8dc403SDave Cobbley ''' 892eb8dc403SDave Cobbley 893eb8dc403SDave Cobbley release_template = ''' 894eb8dc403SDave Cobbley <span data-project-field="release"> 895eb8dc403SDave Cobbley {% if data.release %} 896eb8dc403SDave Cobbley {{data.release.name}} 897eb8dc403SDave Cobbley {% elif data.is_default %} 898eb8dc403SDave Cobbley <span class="text-muted">Not applicable</span> 899eb8dc403SDave Cobbley <span class="glyphicon glyphicon-question-sign get-help hover-help" 900eb8dc403SDave Cobbley title="This project does not have a release set. 901eb8dc403SDave Cobbley It simply collects information about the builds you start from 902eb8dc403SDave Cobbley the command line while Toaster is running" 903eb8dc403SDave Cobbley style="visibility: hidden;"> 904eb8dc403SDave Cobbley </span> 905eb8dc403SDave Cobbley {% else %} 906eb8dc403SDave Cobbley No release available 907eb8dc403SDave Cobbley {% endif %} 908eb8dc403SDave Cobbley </span> 909eb8dc403SDave Cobbley ''' 910eb8dc403SDave Cobbley 911eb8dc403SDave Cobbley machine_template = ''' 912eb8dc403SDave Cobbley <span data-project-field="machine"> 913eb8dc403SDave Cobbley {% if data.is_default %} 914eb8dc403SDave Cobbley <span class="text-muted">Not applicable</span> 915eb8dc403SDave Cobbley <span class="glyphicon glyphicon-question-sign get-help hover-help" 916eb8dc403SDave Cobbley title="This project does not have a machine 917eb8dc403SDave Cobbley set. It simply collects information about the builds you 918eb8dc403SDave Cobbley start from the command line while Toaster is running" 919eb8dc403SDave Cobbley style="visibility: hidden;"></span> 920eb8dc403SDave Cobbley {% else %} 921eb8dc403SDave Cobbley {{data.get_current_machine_name}} 922eb8dc403SDave Cobbley {% endif %} 923eb8dc403SDave Cobbley </span> 924eb8dc403SDave Cobbley ''' 925eb8dc403SDave Cobbley 926eb8dc403SDave Cobbley number_of_builds_template = ''' 927eb8dc403SDave Cobbley {% if data.get_number_of_builds > 0 %} 928eb8dc403SDave Cobbley <a href="{% url 'projectbuilds' data.id %}"> 929eb8dc403SDave Cobbley {{data.get_number_of_builds}} 930eb8dc403SDave Cobbley </a> 931eb8dc403SDave Cobbley {% endif %} 932eb8dc403SDave Cobbley ''' 933eb8dc403SDave Cobbley 934eb8dc403SDave Cobbley last_build_outcome_template = ''' 935eb8dc403SDave Cobbley {% if data.get_number_of_builds > 0 %} 936eb8dc403SDave Cobbley {% if data.get_last_outcome == extra.Build.SUCCEEDED %} 937eb8dc403SDave Cobbley <span class="glyphicon glyphicon-ok-circle"></span> 938eb8dc403SDave Cobbley {% elif data.get_last_outcome == extra.Build.FAILED %} 939eb8dc403SDave Cobbley <span class="glyphicon glyphicon-minus-sign"></span> 940eb8dc403SDave Cobbley {% endif %} 941eb8dc403SDave Cobbley {% endif %} 942eb8dc403SDave Cobbley ''' 943eb8dc403SDave Cobbley 944eb8dc403SDave Cobbley recipe_template = ''' 945eb8dc403SDave Cobbley {% if data.get_number_of_builds > 0 %} 946eb8dc403SDave Cobbley <a href="{% url "builddashboard" data.get_last_build_id %}"> 947eb8dc403SDave Cobbley {{data.get_last_target}} 948eb8dc403SDave Cobbley </a> 949eb8dc403SDave Cobbley {% endif %} 950eb8dc403SDave Cobbley ''' 951eb8dc403SDave Cobbley 952eb8dc403SDave Cobbley errors_template = ''' 953eb8dc403SDave Cobbley {% if data.get_number_of_builds > 0 and data.get_last_errors > 0 %} 954eb8dc403SDave Cobbley <a class="errors.count text-danger" 955eb8dc403SDave Cobbley href="{% url "builddashboard" data.get_last_build_id %}#errors"> 956eb8dc403SDave Cobbley {{data.get_last_errors}} error{{data.get_last_errors | pluralize}} 957eb8dc403SDave Cobbley </a> 958eb8dc403SDave Cobbley {% endif %} 959eb8dc403SDave Cobbley ''' 960eb8dc403SDave Cobbley 961eb8dc403SDave Cobbley warnings_template = ''' 962eb8dc403SDave Cobbley {% if data.get_number_of_builds > 0 and data.get_last_warnings > 0 %} 963eb8dc403SDave Cobbley <a class="warnings.count text-warning" 964eb8dc403SDave Cobbley href="{% url "builddashboard" data.get_last_build_id %}#warnings"> 965eb8dc403SDave Cobbley {{data.get_last_warnings}} warning{{data.get_last_warnings | pluralize}} 966eb8dc403SDave Cobbley </a> 967eb8dc403SDave Cobbley {% endif %} 968eb8dc403SDave Cobbley ''' 969eb8dc403SDave Cobbley 970eb8dc403SDave Cobbley image_files_template = ''' 971eb8dc403SDave Cobbley {% if data.get_number_of_builds > 0 and data.get_last_outcome == extra.Build.SUCCEEDED %} 972eb8dc403SDave Cobbley {{data.get_last_build_extensions}} 973eb8dc403SDave Cobbley {% endif %} 974eb8dc403SDave Cobbley ''' 975eb8dc403SDave Cobbley 976eb8dc403SDave Cobbley self.add_column(title='Project', 977eb8dc403SDave Cobbley hideable=False, 978eb8dc403SDave Cobbley orderable=True, 979eb8dc403SDave Cobbley static_data_name='name', 980eb8dc403SDave Cobbley static_data_template=name_template) 981eb8dc403SDave Cobbley 982eb8dc403SDave Cobbley self.add_column(title='Last activity on', 983eb8dc403SDave Cobbley help_text='Starting date and time of the \ 984eb8dc403SDave Cobbley last project build. If the project has no \ 985eb8dc403SDave Cobbley builds, this shows the date the project was \ 986eb8dc403SDave Cobbley created.', 987eb8dc403SDave Cobbley hideable=False, 988eb8dc403SDave Cobbley orderable=True, 989eb8dc403SDave Cobbley static_data_name='updated', 990eb8dc403SDave Cobbley static_data_template=last_activity_on_template) 991eb8dc403SDave Cobbley 992eb8dc403SDave Cobbley self.add_column(title='Release', 993eb8dc403SDave Cobbley help_text='The version of the build system used by \ 994eb8dc403SDave Cobbley the project', 995eb8dc403SDave Cobbley hideable=False, 996eb8dc403SDave Cobbley orderable=True, 997eb8dc403SDave Cobbley static_data_name='release', 998eb8dc403SDave Cobbley static_data_template=release_template) 999eb8dc403SDave Cobbley 1000eb8dc403SDave Cobbley self.add_column(title='Machine', 1001eb8dc403SDave Cobbley help_text='The hardware currently selected for the \ 1002eb8dc403SDave Cobbley project', 1003eb8dc403SDave Cobbley hideable=False, 1004eb8dc403SDave Cobbley orderable=False, 1005eb8dc403SDave Cobbley static_data_name='machine', 1006eb8dc403SDave Cobbley static_data_template=machine_template) 1007eb8dc403SDave Cobbley 1008eb8dc403SDave Cobbley self.add_column(title='Builds', 1009eb8dc403SDave Cobbley help_text='The number of builds which have been run \ 1010eb8dc403SDave Cobbley for the project', 1011eb8dc403SDave Cobbley hideable=False, 1012eb8dc403SDave Cobbley orderable=False, 1013eb8dc403SDave Cobbley static_data_name='number_of_builds', 1014eb8dc403SDave Cobbley static_data_template=number_of_builds_template) 1015eb8dc403SDave Cobbley 1016eb8dc403SDave Cobbley self.add_column(title='Last build outcome', 1017eb8dc403SDave Cobbley help_text='Indicates whether the last project build \ 1018eb8dc403SDave Cobbley completed successfully or failed', 1019eb8dc403SDave Cobbley hideable=True, 1020eb8dc403SDave Cobbley orderable=False, 1021eb8dc403SDave Cobbley static_data_name='last_build_outcome', 1022eb8dc403SDave Cobbley static_data_template=last_build_outcome_template) 1023eb8dc403SDave Cobbley 1024eb8dc403SDave Cobbley self.add_column(title='Recipe', 1025eb8dc403SDave Cobbley help_text='The last recipe which was built in this \ 1026eb8dc403SDave Cobbley project', 1027eb8dc403SDave Cobbley hideable=True, 1028eb8dc403SDave Cobbley orderable=False, 1029eb8dc403SDave Cobbley static_data_name='recipe_name', 1030eb8dc403SDave Cobbley static_data_template=recipe_template) 1031eb8dc403SDave Cobbley 1032eb8dc403SDave Cobbley self.add_column(title='Errors', 1033eb8dc403SDave Cobbley help_text='The number of errors encountered during \ 1034eb8dc403SDave Cobbley the last project build (if any)', 1035eb8dc403SDave Cobbley hideable=True, 1036eb8dc403SDave Cobbley orderable=False, 1037eb8dc403SDave Cobbley static_data_name='errors', 1038eb8dc403SDave Cobbley static_data_template=errors_template) 1039eb8dc403SDave Cobbley 1040eb8dc403SDave Cobbley self.add_column(title='Warnings', 1041eb8dc403SDave Cobbley help_text='The number of warnings encountered during \ 1042eb8dc403SDave Cobbley the last project build (if any)', 1043eb8dc403SDave Cobbley hideable=True, 1044eb8dc403SDave Cobbley hidden=True, 1045eb8dc403SDave Cobbley orderable=False, 1046eb8dc403SDave Cobbley static_data_name='warnings', 1047eb8dc403SDave Cobbley static_data_template=warnings_template) 1048eb8dc403SDave Cobbley 1049eb8dc403SDave Cobbley self.add_column(title='Image files', 1050eb8dc403SDave Cobbley help_text='The root file system types produced by \ 1051eb8dc403SDave Cobbley the last project build', 1052eb8dc403SDave Cobbley hideable=True, 1053eb8dc403SDave Cobbley hidden=True, 1054eb8dc403SDave Cobbley orderable=False, 1055eb8dc403SDave Cobbley static_data_name='image_files', 1056eb8dc403SDave Cobbley static_data_template=image_files_template) 1057eb8dc403SDave Cobbley 1058eb8dc403SDave Cobbleyclass BuildsTable(ToasterTable): 1059eb8dc403SDave Cobbley """Table of builds in Toaster""" 1060eb8dc403SDave Cobbley 1061eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 1062eb8dc403SDave Cobbley super(BuildsTable, self).__init__(*args, **kwargs) 1063eb8dc403SDave Cobbley self.default_orderby = '-completed_on' 1064eb8dc403SDave Cobbley self.static_context_extra['Build'] = Build 1065eb8dc403SDave Cobbley self.static_context_extra['Task'] = Task 1066eb8dc403SDave Cobbley 1067eb8dc403SDave Cobbley # attributes that are overridden in subclasses 1068eb8dc403SDave Cobbley 1069eb8dc403SDave Cobbley # title for the page 1070eb8dc403SDave Cobbley self.title = '' 1071eb8dc403SDave Cobbley 1072eb8dc403SDave Cobbley # 'project' or 'all'; determines how the mrb (most recent builds) 1073eb8dc403SDave Cobbley # section is displayed 1074eb8dc403SDave Cobbley self.mrb_type = '' 1075eb8dc403SDave Cobbley 1076eb8dc403SDave Cobbley def get_builds(self): 1077eb8dc403SDave Cobbley """ 1078eb8dc403SDave Cobbley overridden in ProjectBuildsTable to return builds for a 1079eb8dc403SDave Cobbley single project 1080eb8dc403SDave Cobbley """ 1081eb8dc403SDave Cobbley return Build.objects.all() 1082eb8dc403SDave Cobbley 1083eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 1084eb8dc403SDave Cobbley context = super(BuildsTable, self).get_context_data(**kwargs) 1085eb8dc403SDave Cobbley 1086eb8dc403SDave Cobbley # should be set in subclasses 1087eb8dc403SDave Cobbley context['mru'] = [] 1088eb8dc403SDave Cobbley 1089eb8dc403SDave Cobbley context['mrb_type'] = self.mrb_type 1090eb8dc403SDave Cobbley 1091eb8dc403SDave Cobbley return context 1092eb8dc403SDave Cobbley 1093eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 1094eb8dc403SDave Cobbley """ 1095eb8dc403SDave Cobbley The queryset is annotated so that it can be sorted by number of 1096eb8dc403SDave Cobbley errors and number of warnings; but note that the criteria for 1097eb8dc403SDave Cobbley finding the log messages to populate these fields should match those 1098eb8dc403SDave Cobbley used in the Build model (orm/models.py) to populate the errors and 1099eb8dc403SDave Cobbley warnings properties 1100eb8dc403SDave Cobbley """ 1101eb8dc403SDave Cobbley queryset = self.get_builds() 1102eb8dc403SDave Cobbley 1103eb8dc403SDave Cobbley # Don't include in progress builds pr cancelled builds 1104eb8dc403SDave Cobbley queryset = queryset.exclude(Q(outcome=Build.IN_PROGRESS) | 1105eb8dc403SDave Cobbley Q(outcome=Build.CANCELLED)) 1106eb8dc403SDave Cobbley 1107eb8dc403SDave Cobbley # sort 1108eb8dc403SDave Cobbley queryset = queryset.order_by(self.default_orderby) 1109eb8dc403SDave Cobbley 1110eb8dc403SDave Cobbley # annotate with number of ERROR, EXCEPTION and CRITICAL log messages 1111eb8dc403SDave Cobbley criteria = (Q(logmessage__level=LogMessage.ERROR) | 1112eb8dc403SDave Cobbley Q(logmessage__level=LogMessage.EXCEPTION) | 1113eb8dc403SDave Cobbley Q(logmessage__level=LogMessage.CRITICAL)) 1114eb8dc403SDave Cobbley 1115eb8dc403SDave Cobbley queryset = queryset.annotate( 1116eb8dc403SDave Cobbley errors_no=Count( 1117eb8dc403SDave Cobbley Case( 1118eb8dc403SDave Cobbley When(criteria, then=Value(1)), 1119eb8dc403SDave Cobbley output_field=IntegerField() 1120eb8dc403SDave Cobbley ) 1121eb8dc403SDave Cobbley ) 1122eb8dc403SDave Cobbley ) 1123eb8dc403SDave Cobbley 1124eb8dc403SDave Cobbley # annotate with number of WARNING log messages 1125eb8dc403SDave Cobbley queryset = queryset.annotate( 1126eb8dc403SDave Cobbley warnings_no=Count( 1127eb8dc403SDave Cobbley Case( 1128eb8dc403SDave Cobbley When(logmessage__level=LogMessage.WARNING, then=Value(1)), 1129eb8dc403SDave Cobbley output_field=IntegerField() 1130eb8dc403SDave Cobbley ) 1131eb8dc403SDave Cobbley ) 1132eb8dc403SDave Cobbley ) 1133eb8dc403SDave Cobbley 1134eb8dc403SDave Cobbley self.queryset = queryset 1135eb8dc403SDave Cobbley 1136eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 1137eb8dc403SDave Cobbley outcome_template = ''' 1138eb8dc403SDave Cobbley {% if data.outcome == data.SUCCEEDED %} 1139eb8dc403SDave Cobbley <span class="glyphicon glyphicon-ok-circle"></span> 1140eb8dc403SDave Cobbley {% elif data.outcome == data.FAILED %} 1141eb8dc403SDave Cobbley <span class="glyphicon glyphicon-minus-sign"></span> 1142eb8dc403SDave Cobbley {% endif %} 1143eb8dc403SDave Cobbley 1144eb8dc403SDave Cobbley {% if data.cooker_log_path %} 1145eb8dc403SDave Cobbley 1146eb8dc403SDave Cobbley <a href="{% url "build_artifact" data.id "cookerlog" data.id %}"> 1147eb8dc403SDave Cobbley <span class="glyphicon glyphicon-download-alt get-help" 1148eb8dc403SDave Cobbley data-original-title="Download build log"></span> 1149eb8dc403SDave Cobbley </a> 1150eb8dc403SDave Cobbley {% endif %} 1151eb8dc403SDave Cobbley ''' 1152eb8dc403SDave Cobbley 1153eb8dc403SDave Cobbley recipe_template = ''' 1154eb8dc403SDave Cobbley {% for target_label in data.target_labels %} 1155eb8dc403SDave Cobbley <a href="{% url "builddashboard" data.id %}"> 1156eb8dc403SDave Cobbley {{target_label}} 1157eb8dc403SDave Cobbley </a> 1158eb8dc403SDave Cobbley <br /> 1159eb8dc403SDave Cobbley {% endfor %} 1160eb8dc403SDave Cobbley ''' 1161eb8dc403SDave Cobbley 1162eb8dc403SDave Cobbley machine_template = ''' 1163eb8dc403SDave Cobbley {{data.machine}} 1164eb8dc403SDave Cobbley ''' 1165eb8dc403SDave Cobbley 1166eb8dc403SDave Cobbley started_on_template = ''' 1167eb8dc403SDave Cobbley {{data.started_on | date:"d/m/y H:i"}} 1168eb8dc403SDave Cobbley ''' 1169eb8dc403SDave Cobbley 1170eb8dc403SDave Cobbley completed_on_template = ''' 1171eb8dc403SDave Cobbley {{data.completed_on | date:"d/m/y H:i"}} 1172eb8dc403SDave Cobbley ''' 1173eb8dc403SDave Cobbley 1174eb8dc403SDave Cobbley failed_tasks_template = ''' 1175eb8dc403SDave Cobbley {% if data.failed_tasks.count == 1 %} 1176eb8dc403SDave Cobbley <a class="text-danger" href="{% url "task" data.id data.failed_tasks.0.id %}"> 1177eb8dc403SDave Cobbley <span> 1178eb8dc403SDave Cobbley {{data.failed_tasks.0.recipe.name}} {{data.failed_tasks.0.task_name}} 1179eb8dc403SDave Cobbley </span> 1180eb8dc403SDave Cobbley </a> 1181eb8dc403SDave Cobbley <a href="{% url "build_artifact" data.id "tasklogfile" data.failed_tasks.0.id %}"> 1182eb8dc403SDave Cobbley <span class="glyphicon glyphicon-download-alt get-help" 1183eb8dc403SDave Cobbley title="Download task log file"> 1184eb8dc403SDave Cobbley </span> 1185eb8dc403SDave Cobbley </a> 1186eb8dc403SDave Cobbley {% elif data.failed_tasks.count > 1 %} 1187eb8dc403SDave Cobbley <a href="{% url "tasks" data.id %}?filter=outcome%3A{{extra.Task.OUTCOME_FAILED}}"> 1188eb8dc403SDave Cobbley <span class="text-danger">{{data.failed_tasks.count}} tasks</span> 1189eb8dc403SDave Cobbley </a> 1190eb8dc403SDave Cobbley {% endif %} 1191eb8dc403SDave Cobbley ''' 1192eb8dc403SDave Cobbley 1193eb8dc403SDave Cobbley errors_template = ''' 1194eb8dc403SDave Cobbley {% if data.errors_no %} 1195eb8dc403SDave Cobbley <a class="errors.count text-danger" href="{% url "builddashboard" data.id %}#errors"> 1196eb8dc403SDave Cobbley {{data.errors_no}} error{{data.errors_no|pluralize}} 1197eb8dc403SDave Cobbley </a> 1198eb8dc403SDave Cobbley {% endif %} 1199eb8dc403SDave Cobbley ''' 1200eb8dc403SDave Cobbley 1201eb8dc403SDave Cobbley warnings_template = ''' 1202eb8dc403SDave Cobbley {% if data.warnings_no %} 1203eb8dc403SDave Cobbley <a class="warnings.count text-warning" href="{% url "builddashboard" data.id %}#warnings"> 1204eb8dc403SDave Cobbley {{data.warnings_no}} warning{{data.warnings_no|pluralize}} 1205eb8dc403SDave Cobbley </a> 1206eb8dc403SDave Cobbley {% endif %} 1207eb8dc403SDave Cobbley ''' 1208eb8dc403SDave Cobbley 1209eb8dc403SDave Cobbley time_template = ''' 1210eb8dc403SDave Cobbley {% load projecttags %} 1211eb8dc403SDave Cobbley {% if data.outcome == extra.Build.SUCCEEDED %} 1212eb8dc403SDave Cobbley <a href="{% url "buildtime" data.id %}"> 1213eb8dc403SDave Cobbley {{data.timespent_seconds | sectohms}} 1214eb8dc403SDave Cobbley </a> 1215eb8dc403SDave Cobbley {% else %} 1216eb8dc403SDave Cobbley {{data.timespent_seconds | sectohms}} 1217eb8dc403SDave Cobbley {% endif %} 1218eb8dc403SDave Cobbley ''' 1219eb8dc403SDave Cobbley 1220eb8dc403SDave Cobbley image_files_template = ''' 1221eb8dc403SDave Cobbley {% if data.outcome == extra.Build.SUCCEEDED %} 1222eb8dc403SDave Cobbley {{data.get_image_file_extensions}} 1223eb8dc403SDave Cobbley {% endif %} 1224eb8dc403SDave Cobbley ''' 1225eb8dc403SDave Cobbley 1226eb8dc403SDave Cobbley self.add_column(title='Outcome', 1227eb8dc403SDave Cobbley help_text='Final state of the build (successful \ 1228eb8dc403SDave Cobbley or failed)', 1229eb8dc403SDave Cobbley hideable=False, 1230eb8dc403SDave Cobbley orderable=True, 1231eb8dc403SDave Cobbley filter_name='outcome_filter', 1232eb8dc403SDave Cobbley static_data_name='outcome', 1233eb8dc403SDave Cobbley static_data_template=outcome_template) 1234eb8dc403SDave Cobbley 1235eb8dc403SDave Cobbley self.add_column(title='Recipe', 1236eb8dc403SDave Cobbley help_text='What was built (i.e. one or more recipes \ 1237eb8dc403SDave Cobbley or image recipes)', 1238eb8dc403SDave Cobbley hideable=False, 1239eb8dc403SDave Cobbley orderable=False, 1240eb8dc403SDave Cobbley static_data_name='target', 1241eb8dc403SDave Cobbley static_data_template=recipe_template) 1242eb8dc403SDave Cobbley 1243eb8dc403SDave Cobbley self.add_column(title='Machine', 1244eb8dc403SDave Cobbley help_text='Hardware for which you are building a \ 1245eb8dc403SDave Cobbley recipe or image recipe', 1246eb8dc403SDave Cobbley hideable=False, 1247eb8dc403SDave Cobbley orderable=True, 1248eb8dc403SDave Cobbley static_data_name='machine', 1249eb8dc403SDave Cobbley static_data_template=machine_template) 1250eb8dc403SDave Cobbley 1251eb8dc403SDave Cobbley self.add_column(title='Started on', 1252eb8dc403SDave Cobbley help_text='The date and time when the build started', 1253eb8dc403SDave Cobbley hideable=True, 1254eb8dc403SDave Cobbley hidden=True, 1255eb8dc403SDave Cobbley orderable=True, 1256eb8dc403SDave Cobbley filter_name='started_on_filter', 1257eb8dc403SDave Cobbley static_data_name='started_on', 1258eb8dc403SDave Cobbley static_data_template=started_on_template) 1259eb8dc403SDave Cobbley 1260eb8dc403SDave Cobbley self.add_column(title='Completed on', 1261eb8dc403SDave Cobbley help_text='The date and time when the build finished', 1262eb8dc403SDave Cobbley hideable=False, 1263eb8dc403SDave Cobbley orderable=True, 1264eb8dc403SDave Cobbley filter_name='completed_on_filter', 1265eb8dc403SDave Cobbley static_data_name='completed_on', 1266eb8dc403SDave Cobbley static_data_template=completed_on_template) 1267eb8dc403SDave Cobbley 1268eb8dc403SDave Cobbley self.add_column(title='Failed tasks', 1269eb8dc403SDave Cobbley help_text='The number of tasks which failed during \ 1270eb8dc403SDave Cobbley the build', 1271eb8dc403SDave Cobbley hideable=True, 1272eb8dc403SDave Cobbley orderable=False, 1273eb8dc403SDave Cobbley filter_name='failed_tasks_filter', 1274eb8dc403SDave Cobbley static_data_name='failed_tasks', 1275eb8dc403SDave Cobbley static_data_template=failed_tasks_template) 1276eb8dc403SDave Cobbley 1277eb8dc403SDave Cobbley self.add_column(title='Errors', 1278eb8dc403SDave Cobbley help_text='The number of errors encountered during \ 1279eb8dc403SDave Cobbley the build (if any)', 1280eb8dc403SDave Cobbley hideable=True, 1281eb8dc403SDave Cobbley orderable=True, 1282eb8dc403SDave Cobbley static_data_name='errors_no', 1283eb8dc403SDave Cobbley static_data_template=errors_template) 1284eb8dc403SDave Cobbley 1285eb8dc403SDave Cobbley self.add_column(title='Warnings', 1286eb8dc403SDave Cobbley help_text='The number of warnings encountered during \ 1287eb8dc403SDave Cobbley the build (if any)', 1288eb8dc403SDave Cobbley hideable=True, 1289eb8dc403SDave Cobbley orderable=True, 1290eb8dc403SDave Cobbley static_data_name='warnings_no', 1291eb8dc403SDave Cobbley static_data_template=warnings_template) 1292eb8dc403SDave Cobbley 1293eb8dc403SDave Cobbley self.add_column(title='Time', 1294eb8dc403SDave Cobbley help_text='How long the build took to finish', 1295eb8dc403SDave Cobbley hideable=True, 1296eb8dc403SDave Cobbley hidden=True, 1297eb8dc403SDave Cobbley orderable=False, 1298eb8dc403SDave Cobbley static_data_name='time', 1299eb8dc403SDave Cobbley static_data_template=time_template) 1300eb8dc403SDave Cobbley 1301eb8dc403SDave Cobbley self.add_column(title='Image files', 1302eb8dc403SDave Cobbley help_text='The root file system types produced by \ 1303eb8dc403SDave Cobbley the build', 1304eb8dc403SDave Cobbley hideable=True, 1305eb8dc403SDave Cobbley orderable=False, 1306eb8dc403SDave Cobbley static_data_name='image_files', 1307eb8dc403SDave Cobbley static_data_template=image_files_template) 1308eb8dc403SDave Cobbley 1309eb8dc403SDave Cobbley def setup_filters(self, *args, **kwargs): 1310eb8dc403SDave Cobbley # outcomes 1311eb8dc403SDave Cobbley outcome_filter = TableFilter( 1312eb8dc403SDave Cobbley 'outcome_filter', 1313eb8dc403SDave Cobbley 'Filter builds by outcome' 1314eb8dc403SDave Cobbley ) 1315eb8dc403SDave Cobbley 1316eb8dc403SDave Cobbley successful_builds_action = TableFilterActionToggle( 1317eb8dc403SDave Cobbley 'successful_builds', 1318eb8dc403SDave Cobbley 'Successful builds', 1319eb8dc403SDave Cobbley Q(outcome=Build.SUCCEEDED) 1320eb8dc403SDave Cobbley ) 1321eb8dc403SDave Cobbley 1322eb8dc403SDave Cobbley failed_builds_action = TableFilterActionToggle( 1323eb8dc403SDave Cobbley 'failed_builds', 1324eb8dc403SDave Cobbley 'Failed builds', 1325eb8dc403SDave Cobbley Q(outcome=Build.FAILED) 1326eb8dc403SDave Cobbley ) 1327eb8dc403SDave Cobbley 1328eb8dc403SDave Cobbley outcome_filter.add_action(successful_builds_action) 1329eb8dc403SDave Cobbley outcome_filter.add_action(failed_builds_action) 1330eb8dc403SDave Cobbley self.add_filter(outcome_filter) 1331eb8dc403SDave Cobbley 1332eb8dc403SDave Cobbley # started on 1333eb8dc403SDave Cobbley started_on_filter = TableFilter( 1334eb8dc403SDave Cobbley 'started_on_filter', 1335eb8dc403SDave Cobbley 'Filter by date when build was started' 1336eb8dc403SDave Cobbley ) 1337eb8dc403SDave Cobbley 1338eb8dc403SDave Cobbley started_today_action = TableFilterActionDay( 1339eb8dc403SDave Cobbley 'today', 1340eb8dc403SDave Cobbley 'Today\'s builds', 1341eb8dc403SDave Cobbley 'started_on', 1342eb8dc403SDave Cobbley 'today' 1343eb8dc403SDave Cobbley ) 1344eb8dc403SDave Cobbley 1345eb8dc403SDave Cobbley started_yesterday_action = TableFilterActionDay( 1346eb8dc403SDave Cobbley 'yesterday', 1347eb8dc403SDave Cobbley 'Yesterday\'s builds', 1348eb8dc403SDave Cobbley 'started_on', 1349eb8dc403SDave Cobbley 'yesterday' 1350eb8dc403SDave Cobbley ) 1351eb8dc403SDave Cobbley 1352eb8dc403SDave Cobbley by_started_date_range_action = TableFilterActionDateRange( 1353eb8dc403SDave Cobbley 'date_range', 1354eb8dc403SDave Cobbley 'Build date range', 1355eb8dc403SDave Cobbley 'started_on' 1356eb8dc403SDave Cobbley ) 1357eb8dc403SDave Cobbley 1358eb8dc403SDave Cobbley started_on_filter.add_action(started_today_action) 1359eb8dc403SDave Cobbley started_on_filter.add_action(started_yesterday_action) 1360eb8dc403SDave Cobbley started_on_filter.add_action(by_started_date_range_action) 1361eb8dc403SDave Cobbley self.add_filter(started_on_filter) 1362eb8dc403SDave Cobbley 1363eb8dc403SDave Cobbley # completed on 1364eb8dc403SDave Cobbley completed_on_filter = TableFilter( 1365eb8dc403SDave Cobbley 'completed_on_filter', 1366eb8dc403SDave Cobbley 'Filter by date when build was completed' 1367eb8dc403SDave Cobbley ) 1368eb8dc403SDave Cobbley 1369eb8dc403SDave Cobbley completed_today_action = TableFilterActionDay( 1370eb8dc403SDave Cobbley 'today', 1371eb8dc403SDave Cobbley 'Today\'s builds', 1372eb8dc403SDave Cobbley 'completed_on', 1373eb8dc403SDave Cobbley 'today' 1374eb8dc403SDave Cobbley ) 1375eb8dc403SDave Cobbley 1376eb8dc403SDave Cobbley completed_yesterday_action = TableFilterActionDay( 1377eb8dc403SDave Cobbley 'yesterday', 1378eb8dc403SDave Cobbley 'Yesterday\'s builds', 1379eb8dc403SDave Cobbley 'completed_on', 1380eb8dc403SDave Cobbley 'yesterday' 1381eb8dc403SDave Cobbley ) 1382eb8dc403SDave Cobbley 1383eb8dc403SDave Cobbley by_completed_date_range_action = TableFilterActionDateRange( 1384eb8dc403SDave Cobbley 'date_range', 1385eb8dc403SDave Cobbley 'Build date range', 1386eb8dc403SDave Cobbley 'completed_on' 1387eb8dc403SDave Cobbley ) 1388eb8dc403SDave Cobbley 1389eb8dc403SDave Cobbley completed_on_filter.add_action(completed_today_action) 1390eb8dc403SDave Cobbley completed_on_filter.add_action(completed_yesterday_action) 1391eb8dc403SDave Cobbley completed_on_filter.add_action(by_completed_date_range_action) 1392eb8dc403SDave Cobbley self.add_filter(completed_on_filter) 1393eb8dc403SDave Cobbley 1394eb8dc403SDave Cobbley # failed tasks 1395eb8dc403SDave Cobbley failed_tasks_filter = TableFilter( 1396eb8dc403SDave Cobbley 'failed_tasks_filter', 1397eb8dc403SDave Cobbley 'Filter builds by failed tasks' 1398eb8dc403SDave Cobbley ) 1399eb8dc403SDave Cobbley 1400eb8dc403SDave Cobbley criteria = Q(task_build__outcome=Task.OUTCOME_FAILED) 1401eb8dc403SDave Cobbley 1402eb8dc403SDave Cobbley with_failed_tasks_action = TableFilterActionToggle( 1403eb8dc403SDave Cobbley 'with_failed_tasks', 1404eb8dc403SDave Cobbley 'Builds with failed tasks', 1405eb8dc403SDave Cobbley criteria 1406eb8dc403SDave Cobbley ) 1407eb8dc403SDave Cobbley 1408eb8dc403SDave Cobbley without_failed_tasks_action = TableFilterActionToggle( 1409eb8dc403SDave Cobbley 'without_failed_tasks', 1410eb8dc403SDave Cobbley 'Builds without failed tasks', 1411eb8dc403SDave Cobbley ~criteria 1412eb8dc403SDave Cobbley ) 1413eb8dc403SDave Cobbley 1414eb8dc403SDave Cobbley failed_tasks_filter.add_action(with_failed_tasks_action) 1415eb8dc403SDave Cobbley failed_tasks_filter.add_action(without_failed_tasks_action) 1416eb8dc403SDave Cobbley self.add_filter(failed_tasks_filter) 1417eb8dc403SDave Cobbley 1418eb8dc403SDave Cobbley 1419eb8dc403SDave Cobbleyclass AllBuildsTable(BuildsTable): 1420eb8dc403SDave Cobbley """ Builds page for all builds """ 1421eb8dc403SDave Cobbley 1422eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 1423eb8dc403SDave Cobbley super(AllBuildsTable, self).__init__(*args, **kwargs) 1424eb8dc403SDave Cobbley self.title = 'All builds' 1425eb8dc403SDave Cobbley self.mrb_type = 'all' 1426eb8dc403SDave Cobbley 1427eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 1428eb8dc403SDave Cobbley """ 1429eb8dc403SDave Cobbley All builds page shows a column for the project 1430eb8dc403SDave Cobbley """ 1431eb8dc403SDave Cobbley 1432eb8dc403SDave Cobbley super(AllBuildsTable, self).setup_columns(*args, **kwargs) 1433eb8dc403SDave Cobbley 1434eb8dc403SDave Cobbley project_template = ''' 1435eb8dc403SDave Cobbley {% load project_url_tag %} 1436eb8dc403SDave Cobbley <a href="{% project_url data.project %}"> 1437eb8dc403SDave Cobbley {{data.project.name}} 1438eb8dc403SDave Cobbley </a> 1439eb8dc403SDave Cobbley {% if data.project.is_default %} 1440eb8dc403SDave Cobbley <span class="glyphicon glyphicon-question-sign get-help hover-help" title="" 1441eb8dc403SDave Cobbley data-original-title="This project shows information about 1442eb8dc403SDave Cobbley the builds you start from the command line while Toaster is 1443eb8dc403SDave Cobbley running" style="visibility: hidden;"></span> 1444eb8dc403SDave Cobbley {% endif %} 1445eb8dc403SDave Cobbley ''' 1446eb8dc403SDave Cobbley 1447eb8dc403SDave Cobbley self.add_column(title='Project', 1448eb8dc403SDave Cobbley hideable=True, 1449eb8dc403SDave Cobbley orderable=True, 1450eb8dc403SDave Cobbley static_data_name='project', 1451eb8dc403SDave Cobbley static_data_template=project_template) 1452eb8dc403SDave Cobbley 1453eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 1454eb8dc403SDave Cobbley """ Get all builds for the recent builds area """ 1455eb8dc403SDave Cobbley context = super(AllBuildsTable, self).get_context_data(**kwargs) 1456eb8dc403SDave Cobbley context['mru'] = Build.get_recent() 1457eb8dc403SDave Cobbley return context 1458eb8dc403SDave Cobbley 1459eb8dc403SDave Cobbleyclass ProjectBuildsTable(BuildsTable): 1460eb8dc403SDave Cobbley """ 1461eb8dc403SDave Cobbley Builds page for a single project; a BuildsTable, with the queryset 1462eb8dc403SDave Cobbley filtered by project 1463eb8dc403SDave Cobbley """ 1464eb8dc403SDave Cobbley 1465eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 1466eb8dc403SDave Cobbley super(ProjectBuildsTable, self).__init__(*args, **kwargs) 1467eb8dc403SDave Cobbley self.title = 'All project builds' 1468eb8dc403SDave Cobbley self.mrb_type = 'project' 1469eb8dc403SDave Cobbley 1470eb8dc403SDave Cobbley # set from the querystring 1471eb8dc403SDave Cobbley self.project_id = None 1472eb8dc403SDave Cobbley 1473eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 1474eb8dc403SDave Cobbley """ 1475eb8dc403SDave Cobbley Project builds table doesn't show the machines column by default 1476eb8dc403SDave Cobbley """ 1477eb8dc403SDave Cobbley 1478eb8dc403SDave Cobbley super(ProjectBuildsTable, self).setup_columns(*args, **kwargs) 1479eb8dc403SDave Cobbley 1480eb8dc403SDave Cobbley # hide the machine column 1481eb8dc403SDave Cobbley self.set_column_hidden('Machine', True) 1482eb8dc403SDave Cobbley 1483eb8dc403SDave Cobbley # allow the machine column to be hidden by the user 1484eb8dc403SDave Cobbley self.set_column_hideable('Machine', True) 1485eb8dc403SDave Cobbley 1486eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 1487eb8dc403SDave Cobbley """ 1488eb8dc403SDave Cobbley NOTE: self.project_id must be set before calling super(), 1489eb8dc403SDave Cobbley as it's used in setup_queryset() 1490eb8dc403SDave Cobbley """ 1491eb8dc403SDave Cobbley self.project_id = kwargs['pid'] 1492eb8dc403SDave Cobbley super(ProjectBuildsTable, self).setup_queryset(*args, **kwargs) 1493eb8dc403SDave Cobbley project = Project.objects.get(pk=self.project_id) 1494eb8dc403SDave Cobbley self.queryset = self.queryset.filter(project=project) 1495eb8dc403SDave Cobbley 1496eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 1497eb8dc403SDave Cobbley """ 1498eb8dc403SDave Cobbley Get recent builds for this project, and the project itself 1499eb8dc403SDave Cobbley 1500eb8dc403SDave Cobbley NOTE: self.project_id must be set before calling super(), 1501eb8dc403SDave Cobbley as it's used in get_context_data() 1502eb8dc403SDave Cobbley """ 1503eb8dc403SDave Cobbley self.project_id = kwargs['pid'] 1504eb8dc403SDave Cobbley context = super(ProjectBuildsTable, self).get_context_data(**kwargs) 1505eb8dc403SDave Cobbley 1506eb8dc403SDave Cobbley empty_state_template = ''' 1507eb8dc403SDave Cobbley This project has no builds. 1508eb8dc403SDave Cobbley <a href="{% url 'projectimagerecipes' data.pid %}"> 1509eb8dc403SDave Cobbley Choose a recipe to build</a> 1510eb8dc403SDave Cobbley ''' 1511eb8dc403SDave Cobbley context['empty_state'] = self.render_static_data(empty_state_template, 1512eb8dc403SDave Cobbley kwargs) 1513eb8dc403SDave Cobbley 1514eb8dc403SDave Cobbley project = Project.objects.get(pk=self.project_id) 1515eb8dc403SDave Cobbley context['mru'] = Build.get_recent(project) 1516eb8dc403SDave Cobbley context['project'] = project 1517eb8dc403SDave Cobbley 1518eb8dc403SDave Cobbley self.setup_queryset(**kwargs) 1519eb8dc403SDave Cobbley if self.queryset.count() == 0 and \ 1520eb8dc403SDave Cobbley project.build_set.filter(outcome=Build.IN_PROGRESS).count() > 0: 1521eb8dc403SDave Cobbley context['build_in_progress_none_completed'] = True 1522eb8dc403SDave Cobbley else: 1523eb8dc403SDave Cobbley context['build_in_progress_none_completed'] = False 1524eb8dc403SDave Cobbley 1525eb8dc403SDave Cobbley return context 1526eb8dc403SDave Cobbley 1527eb8dc403SDave Cobbley 1528eb8dc403SDave Cobbleyclass DistrosTable(ToasterTable): 1529eb8dc403SDave Cobbley """Table of Distros in Toaster""" 1530eb8dc403SDave Cobbley 1531eb8dc403SDave Cobbley def __init__(self, *args, **kwargs): 1532eb8dc403SDave Cobbley super(DistrosTable, self).__init__(*args, **kwargs) 1533eb8dc403SDave Cobbley self.empty_state = "Toaster has no distro information for this project. Sadly, distro information cannot be obtained from builds, so this page will remain empty." 1534eb8dc403SDave Cobbley self.title = "Compatible Distros" 1535eb8dc403SDave Cobbley self.default_orderby = "name" 1536eb8dc403SDave Cobbley 1537eb8dc403SDave Cobbley def get_context_data(self, **kwargs): 1538eb8dc403SDave Cobbley context = super(DistrosTable, self).get_context_data(**kwargs) 1539eb8dc403SDave Cobbley context['project'] = Project.objects.get(pk=kwargs['pid']) 1540eb8dc403SDave Cobbley return context 1541eb8dc403SDave Cobbley 1542eb8dc403SDave Cobbley def setup_filters(self, *args, **kwargs): 1543eb8dc403SDave Cobbley project = Project.objects.get(pk=kwargs['pid']) 1544eb8dc403SDave Cobbley 1545eb8dc403SDave Cobbley in_current_project_filter = TableFilter( 1546eb8dc403SDave Cobbley "in_current_project", 1547eb8dc403SDave Cobbley "Filter by project Distros" 1548eb8dc403SDave Cobbley ) 1549eb8dc403SDave Cobbley 1550eb8dc403SDave Cobbley in_project_action = TableFilterActionToggle( 1551eb8dc403SDave Cobbley "in_project", 1552eb8dc403SDave Cobbley "Distro provided by layers added to this project", 1553eb8dc403SDave Cobbley ProjectFilters.in_project(self.project_layers) 1554eb8dc403SDave Cobbley ) 1555eb8dc403SDave Cobbley 1556eb8dc403SDave Cobbley not_in_project_action = TableFilterActionToggle( 1557eb8dc403SDave Cobbley "not_in_project", 1558eb8dc403SDave Cobbley "Distros provided by layers not added to this project", 1559eb8dc403SDave Cobbley ProjectFilters.not_in_project(self.project_layers) 1560eb8dc403SDave Cobbley ) 1561eb8dc403SDave Cobbley 1562eb8dc403SDave Cobbley in_current_project_filter.add_action(in_project_action) 1563eb8dc403SDave Cobbley in_current_project_filter.add_action(not_in_project_action) 1564eb8dc403SDave Cobbley self.add_filter(in_current_project_filter) 1565eb8dc403SDave Cobbley 1566eb8dc403SDave Cobbley def setup_queryset(self, *args, **kwargs): 1567eb8dc403SDave Cobbley prj = Project.objects.get(pk = kwargs['pid']) 1568eb8dc403SDave Cobbley self.queryset = prj.get_all_compatible_distros() 1569eb8dc403SDave Cobbley self.queryset = self.queryset.order_by(self.default_orderby) 1570eb8dc403SDave Cobbley 1571eb8dc403SDave Cobbley self.static_context_extra['current_layers'] = \ 1572eb8dc403SDave Cobbley self.project_layers = \ 1573eb8dc403SDave Cobbley prj.get_project_layer_versions(pk=True) 1574eb8dc403SDave Cobbley 1575eb8dc403SDave Cobbley def setup_columns(self, *args, **kwargs): 1576eb8dc403SDave Cobbley 1577eb8dc403SDave Cobbley self.add_column(title="Distro", 1578eb8dc403SDave Cobbley hideable=False, 1579eb8dc403SDave Cobbley orderable=True, 1580eb8dc403SDave Cobbley field_name="name") 1581eb8dc403SDave Cobbley 1582eb8dc403SDave Cobbley self.add_column(title="Description", 1583eb8dc403SDave Cobbley field_name="description") 1584eb8dc403SDave Cobbley 1585eb8dc403SDave Cobbley layer_link_template = ''' 1586eb8dc403SDave Cobbley <a href="{% url 'layerdetails' extra.pid data.layer_version.id %}"> 1587eb8dc403SDave Cobbley {{data.layer_version.layer.name}}</a> 1588eb8dc403SDave Cobbley ''' 1589eb8dc403SDave Cobbley 1590eb8dc403SDave Cobbley self.add_column(title="Layer", 1591eb8dc403SDave Cobbley static_data_name="layer_version__layer__name", 1592eb8dc403SDave Cobbley static_data_template=layer_link_template, 1593eb8dc403SDave Cobbley orderable=True) 1594eb8dc403SDave Cobbley 1595eb8dc403SDave Cobbley self.add_column(title="Git revision", 1596eb8dc403SDave Cobbley help_text="The Git branch, tag or commit. For the layers from the OpenEmbedded layer source, the revision is always the branch compatible with the Yocto Project version you selected for this project", 1597eb8dc403SDave Cobbley hidden=True, 1598eb8dc403SDave Cobbley field_name="layer_version__get_vcs_reference") 1599eb8dc403SDave Cobbley 16001a4b7ee2SBrad Bishop distro_file_template = '''<code>conf/distro/{{data.name}}.conf</code> 16011a4b7ee2SBrad Bishop {% if 'None' not in data.get_vcs_distro_file_link_url %}<a href="{{data.get_vcs_distro_file_link_url}}" target="_blank"><span class="glyphicon glyphicon-new-window"></i></a>{% endif %}''' 1602eb8dc403SDave Cobbley self.add_column(title="Distro file", 1603eb8dc403SDave Cobbley hidden=True, 1604eb8dc403SDave Cobbley static_data_name="templatefile", 16051a4b7ee2SBrad Bishop static_data_template=distro_file_template) 1606eb8dc403SDave Cobbley 1607eb8dc403SDave Cobbley self.add_column(title="Select", 1608eb8dc403SDave Cobbley help_text="Sets the selected distro to the project", 1609eb8dc403SDave Cobbley hideable=False, 1610eb8dc403SDave Cobbley filter_name="in_current_project", 1611eb8dc403SDave Cobbley static_data_name="add-del-layers", 1612eb8dc403SDave Cobbley static_data_template='{% include "distro_btn.html" %}') 1613eb8dc403SDave Cobbley 1614