diff options
| -rw-r--r-- | bitbake/lib/toaster/toastergui/tables.py | 222 |
1 files changed, 188 insertions, 34 deletions
diff --git a/bitbake/lib/toaster/toastergui/tables.py b/bitbake/lib/toaster/toastergui/tables.py index 70e4b6d782..1526d59004 100644 --- a/bitbake/lib/toaster/toastergui/tables.py +++ b/bitbake/lib/toaster/toastergui/tables.py | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | from toastergui.widgets import ToasterTable | 22 | from toastergui.widgets import ToasterTable |
| 23 | from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project | 23 | from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project |
| 24 | from orm.models import CustomImageRecipe, Package | ||
| 24 | from django.db.models import Q, Max | 25 | from django.db.models import Q, Max |
| 25 | from django.conf.urls import url | 26 | from django.conf.urls import url |
| 26 | from django.core.urlresolvers import reverse | 27 | from django.core.urlresolvers import reverse |
| @@ -310,13 +311,20 @@ class LayerMachinesTable(MachinesTable): | |||
| 310 | 311 | ||
| 311 | 312 | ||
| 312 | class RecipesTable(ToasterTable, ProjectFiltersMixin): | 313 | class RecipesTable(ToasterTable, ProjectFiltersMixin): |
| 313 | """Table of Recipes in Toaster""" | 314 | """Table of All Recipes in Toaster""" |
| 314 | 315 | ||
| 315 | def __init__(self, *args, **kwargs): | 316 | def __init__(self, *args, **kwargs): |
| 316 | super(RecipesTable, self).__init__(*args, **kwargs) | 317 | super(RecipesTable, self).__init__(*args, **kwargs) |
| 317 | self.empty_state = "Toaster has no recipe information. To generate recipe information you can configure a layer source then run a build." | 318 | self.empty_state = "Toaster has no recipe information. To generate recipe information you can configure a layer source then run a build." |
| 318 | self.default_orderby = "name" | 319 | self.default_orderby = "name" |
| 319 | 320 | ||
| 321 | build_col = { 'title' : "Build", | ||
| 322 | 'help_text' : "Add or delete recipes to and from your project", | ||
| 323 | 'hideable' : False, | ||
| 324 | 'filter_name' : "in_current_project", | ||
| 325 | 'static_data_name' : "add-del-layers", | ||
| 326 | 'static_data_template' : '{% include "recipe_btn.html" %}'} | ||
| 327 | |||
| 320 | def get_context_data(self, **kwargs): | 328 | def get_context_data(self, **kwargs): |
| 321 | project = Project.objects.get(pk=kwargs['pid']) | 329 | project = Project.objects.get(pk=kwargs['pid']) |
| 322 | context = super(RecipesTable, self).get_context_data(**kwargs) | 330 | context = super(RecipesTable, self).get_context_data(**kwargs) |
| @@ -327,17 +335,6 @@ class RecipesTable(ToasterTable, ProjectFiltersMixin): | |||
| 327 | 335 | ||
| 328 | return context | 336 | return context |
| 329 | 337 | ||
| 330 | def setup_filters(self, *args, **kwargs): | ||
| 331 | project = Project.objects.get(pk=kwargs['pid']) | ||
| 332 | self.project_layers = project.projectlayer_equivalent_set() | ||
| 333 | |||
| 334 | self.add_filter(title="Filter by project recipes", | ||
| 335 | name="in_current_project", | ||
| 336 | filter_actions=[ | ||
| 337 | self.make_filter_action("in_project", "Recipes provided by layers added to this project", self.filter_in_project), | ||
| 338 | self.make_filter_action("not_in_project", "Recipes provided by layers not added to this project", self.filter_not_in_project) | ||
| 339 | ]) | ||
| 340 | |||
| 341 | 338 | ||
| 342 | def setup_queryset(self, *args, **kwargs): | 339 | def setup_queryset(self, *args, **kwargs): |
| 343 | prj = Project.objects.get(pk = kwargs['pid']) | 340 | prj = Project.objects.get(pk = kwargs['pid']) |
| @@ -348,12 +345,6 @@ class RecipesTable(ToasterTable, ProjectFiltersMixin): | |||
| 348 | 345 | ||
| 349 | def setup_columns(self, *args, **kwargs): | 346 | def setup_columns(self, *args, **kwargs): |
| 350 | 347 | ||
| 351 | self.add_column(title="Recipe", | ||
| 352 | 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", | ||
| 353 | hideable=False, | ||
| 354 | orderable=True, | ||
| 355 | field_name="name") | ||
| 356 | |||
| 357 | self.add_column(title="Recipe Version", | 348 | self.add_column(title="Recipe Version", |
| 358 | hidden=True, | 349 | hidden=True, |
| 359 | field_name="version") | 350 | field_name="version") |
| @@ -398,18 +389,6 @@ class RecipesTable(ToasterTable, ProjectFiltersMixin): | |||
| 398 | self.add_column(title="Revision", | 389 | self.add_column(title="Revision", |
| 399 | field_name="layer_version__get_vcs_reference") | 390 | field_name="layer_version__get_vcs_reference") |
| 400 | 391 | ||
| 401 | self.add_column(title="Build", | ||
| 402 | help_text="Add or delete recipes to and from your project", | ||
| 403 | hideable=False, | ||
| 404 | filter_name="in_current_project", | ||
| 405 | static_data_name="add-del-layers", | ||
| 406 | static_data_template='{% include "recipe_btn.html" %}') | ||
| 407 | |||
| 408 | project = Project.objects.get(pk=kwargs['pid']) | ||
| 409 | self.add_column(title="Project compatible Layer ID", | ||
| 410 | displayable = False, | ||
| 411 | field_name = "projectcompatible_layer", | ||
| 412 | computation = lambda x: (x.layer_version.get_equivalents_wpriority(project)[0])) | ||
| 413 | 392 | ||
| 414 | class LayerRecipesTable(RecipesTable): | 393 | class LayerRecipesTable(RecipesTable): |
| 415 | """ Smaller version of the Recipes table for use in layer details """ | 394 | """ Smaller version of the Recipes table for use in layer details """ |
| @@ -446,10 +425,185 @@ class LayerRecipesTable(RecipesTable): | |||
| 446 | static_data_name="add-del-layers", | 425 | static_data_name="add-del-layers", |
| 447 | static_data_template=build_recipe_template) | 426 | static_data_template=build_recipe_template) |
| 448 | 427 | ||
| 449 | class ProjectLayersRecipesTable(RecipesTable): | 428 | class CustomImagesTable(ToasterTable): |
| 450 | """ Table that lists only recipes available for layers added to the project """ | 429 | """ Table to display your custom images """ |
| 430 | def __init__(self, *args, **kwargs): | ||
| 431 | super(CustomImagesTable, self).__init__(*args, **kwargs) | ||
| 432 | self.title = "Custom images" | ||
| 433 | |||
| 434 | def get_context_data(self, **kwargs): | ||
| 435 | context = super(CustomImagesTable, self).get_context_data(**kwargs) | ||
| 436 | project = Project.objects.get(pk=kwargs['pid']) | ||
| 437 | context['project'] = project | ||
| 438 | context['projectlayers'] = map(lambda prjlayer: prjlayer.layercommit.id, ProjectLayer.objects.filter(project=context['project'])) | ||
| 439 | return context | ||
| 440 | |||
| 441 | def setup_queryset(self, *args, **kwargs): | ||
| 442 | prj = Project.objects.get(pk = kwargs['pid']) | ||
| 443 | self.queryset = CustomImageRecipe.objects.filter(project=prj) | ||
| 444 | self.queryset = self.queryset.order_by('name') | ||
| 445 | |||
| 446 | def setup_columns(self, *args, **kwargs): | ||
| 447 | |||
| 448 | name_link_template = ''' | ||
| 449 | <a href="{% url 'customrecipe' extra.pid data.id %}"> | ||
| 450 | {{data.name}} | ||
| 451 | </a> | ||
| 452 | ''' | ||
| 453 | |||
| 454 | self.add_column(title="Custom image", | ||
| 455 | hideable=False, | ||
| 456 | static_data_name="name", | ||
| 457 | static_data_template=name_link_template) | ||
| 458 | |||
| 459 | self.add_column(title="Recipe file", | ||
| 460 | static_data_name='recipe_file', | ||
| 461 | static_data_template='') | ||
| 462 | |||
| 463 | approx_packages_template = '<a href="#imagedetails">{{data.packages.all|length}}</a>' | ||
| 464 | self.add_column(title="Approx packages", | ||
| 465 | static_data_name='approx_packages', | ||
| 466 | static_data_template=approx_packages_template) | ||
| 467 | |||
| 468 | |||
| 469 | build_btn_template = '''<button data-recipe-name="{{data.name}}" | ||
| 470 | class="btn btn-block build-recipe-btn" style="margin-top: 5px;" > | ||
| 471 | Build</button>''' | ||
| 472 | |||
| 473 | self.add_column(title="Build", | ||
| 474 | hideable=False, | ||
| 475 | static_data_name='build_custom_img', | ||
| 476 | static_data_template=build_btn_template) | ||
| 477 | |||
| 478 | class ImageRecipesTable(RecipesTable): | ||
| 479 | """ A subset of the recipes table which displayed just image recipes """ | ||
| 480 | |||
| 481 | def __init__(self, *args, **kwargs): | ||
| 482 | super(ImageRecipesTable, self).__init__(*args, **kwargs) | ||
| 483 | self.title = "Compatible image recipes" | ||
| 484 | |||
| 485 | def setup_queryset(self, *args, **kwargs): | ||
| 486 | super(ImageRecipesTable, self).setup_queryset(*args, **kwargs) | ||
| 487 | |||
| 488 | self.queryset = self.queryset.filter(is_image=True) | ||
| 489 | |||
| 490 | |||
| 491 | def setup_columns(self, *args, **kwargs): | ||
| 492 | self.add_column(title="Image recipe", | ||
| 493 | help_text="When you build an image recipe, you get an " | ||
| 494 | "image: a root file system you can" | ||
| 495 | "deploy to a machine", | ||
| 496 | hideable=False, | ||
| 497 | orderable=True, | ||
| 498 | field_name="name") | ||
| 499 | |||
| 500 | super(ImageRecipesTable, self).setup_columns(*args, **kwargs) | ||
| 501 | |||
| 502 | self.add_column(**RecipesTable.build_col) | ||
| 503 | |||
| 504 | |||
| 505 | class NewCustomImagesTable(ImageRecipesTable): | ||
| 506 | """ Table which displays Images recipes which can be customised """ | ||
| 507 | def __init__(self, *args, **kwargs): | ||
| 508 | super(NewCustomImagesTable, self).__init__(*args, **kwargs) | ||
| 509 | self.title = "Select the image recipe you want to customise" | ||
| 451 | 510 | ||
| 452 | def setup_queryset(self, *args, **kwargs): | 511 | def setup_queryset(self, *args, **kwargs): |
| 453 | super(ProjectLayersRecipesTable, self).setup_queryset(*args, **kwargs) | 512 | super(ImageRecipesTable, self).setup_queryset(*args, **kwargs) |
| 513 | |||
| 514 | self.queryset = self.queryset.filter(is_image=True) | ||
| 515 | |||
| 516 | def setup_columns(self, *args, **kwargs): | ||
| 517 | self.add_column(title="Image recipe", | ||
| 518 | help_text="When you build an image recipe, you get an " | ||
| 519 | "image: a root file system you can" | ||
| 520 | "deploy to a machine", | ||
| 521 | hideable=False, | ||
| 522 | orderable=True, | ||
| 523 | field_name="recipe__name") | ||
| 524 | |||
| 525 | super(ImageRecipesTable, self).setup_columns(*args, **kwargs) | ||
| 526 | |||
| 527 | self.add_column(title="Customise", | ||
| 528 | hideable=False, | ||
| 529 | filter_name="in_current_project", | ||
| 530 | static_data_name="customise-or-add-recipe", | ||
| 531 | static_data_template='{% include "customise_btn.html" %}') | ||
| 532 | |||
| 533 | |||
| 534 | class SoftwareRecipesTable(RecipesTable): | ||
| 535 | """ Displays just the software recipes """ | ||
| 536 | def __init__(self, *args, **kwargs): | ||
| 537 | super(SoftwareRecipesTable, self).__init__(*args, **kwargs) | ||
| 538 | self.title = "Compatible software recipes" | ||
| 539 | |||
| 540 | def setup_queryset(self, *args, **kwargs): | ||
| 541 | super(SoftwareRecipesTable, self).setup_queryset(*args, **kwargs) | ||
| 542 | |||
| 543 | self.queryset = self.queryset.filter(is_image=False) | ||
| 544 | |||
| 545 | |||
| 546 | def setup_columns(self, *args, **kwargs): | ||
| 547 | self.add_column(title="Software recipe", | ||
| 548 | help_text="Information about a single piece of " | ||
| 549 | "software, including where to download the source, " | ||
| 550 | "configuration options, how to compile the source " | ||
| 551 | "files and how to package the compiled output", | ||
| 552 | hideable=False, | ||
| 553 | orderable=True, | ||
| 554 | field_name="name") | ||
| 555 | |||
| 556 | super(SoftwareRecipesTable, self).setup_columns(*args, **kwargs) | ||
| 557 | |||
| 558 | self.add_column(**RecipesTable.build_col) | ||
| 559 | |||
| 560 | |||
| 561 | class SelectPackagesTable(ToasterTable): | ||
| 562 | """ Table to display the packages to add and remove from an image """ | ||
| 563 | |||
| 564 | def __init__(self, *args, **kwargs): | ||
| 565 | super(SelectPackagesTable, self).__init__(*args, **kwargs) | ||
| 566 | self.title = "Add | Remove packages" | ||
| 567 | |||
| 568 | def setup_queryset(self, *args, **kwargs): | ||
| 569 | cust_recipe = CustomImageRecipe.objects.get(pk=kwargs['recipeid']) | ||
| 454 | prj = Project.objects.get(pk = kwargs['pid']) | 570 | prj = Project.objects.get(pk = kwargs['pid']) |
| 455 | self.queryset = self.queryset.filter(layer_version__in = prj.projectlayer_equivalent_set()) | 571 | |
| 572 | current_packages = cust_recipe.packages.all() | ||
| 573 | |||
| 574 | # Get all the packages that are in the custom image | ||
| 575 | # Get all the packages built by builds in the current project | ||
| 576 | # but not those ones that are already in the custom image | ||
| 577 | self.queryset = Package.objects.filter( | ||
| 578 | Q(pk__in=current_packages) | | ||
| 579 | (Q(build__project=prj) & | ||
| 580 | ~Q(name__in=current_packages.values_list('name')))) | ||
| 581 | |||
| 582 | self.queryset = self.queryset.order_by('name') | ||
| 583 | |||
| 584 | self.static_context_extra['recipe_id'] = kwargs['recipeid'] | ||
| 585 | self.static_context_extra['current_packages'] = \ | ||
| 586 | cust_recipe.packages.values_list('pk', flat=True) | ||
| 587 | |||
| 588 | def setup_columns(self, *args, **kwargs): | ||
| 589 | self.add_column(title="Package", | ||
| 590 | hideable=False, | ||
| 591 | orderable=True, | ||
| 592 | field_name="name") | ||
| 593 | |||
| 594 | self.add_column(title="Package Version", | ||
| 595 | field_name="version") | ||
| 596 | |||
| 597 | self.add_column(title="Approx Size", | ||
| 598 | orderable=True, | ||
| 599 | static_data_name="size", | ||
| 600 | static_data_template="{% load projecttags %} \ | ||
| 601 | {{data.size|filtered_filesizeformat}}") | ||
| 602 | self.add_column(title="summary", | ||
| 603 | field_name="summary") | ||
| 604 | |||
| 605 | self.add_column(title="Add | Remove", | ||
| 606 | help_text="Use the add and remove buttons to modify " | ||
| 607 | "the package content of you custom image", | ||
| 608 | static_data_name="add_rm_pkg_btn", | ||
| 609 | static_data_template='{% include "pkg_add_rm_btn.html" %}') | ||
