diff options
Diffstat (limited to 'bitbake/lib/toaster/orm/models.py')
-rw-r--r-- | bitbake/lib/toaster/orm/models.py | 377 |
1 files changed, 339 insertions, 38 deletions
diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py index f19a4370c8..5a6dcd72f6 100644 --- a/bitbake/lib/toaster/orm/models.py +++ b/bitbake/lib/toaster/orm/models.py | |||
@@ -22,30 +22,33 @@ | |||
22 | from django.db import models | 22 | from django.db import models |
23 | from django.db.models import F | 23 | from django.db.models import F |
24 | from django.utils.encoding import python_2_unicode_compatible | 24 | from django.utils.encoding import python_2_unicode_compatible |
25 | from django.utils import timezone | ||
26 | |||
27 | class ToasterSetting(models.Model): | ||
28 | name = models.CharField(max_length=63) | ||
29 | helptext = models.TextField() | ||
30 | value = models.CharField(max_length=255) | ||
31 | |||
32 | class ToasterSettingDefaultLayer(models.Model): | ||
33 | layer_version = models.ForeignKey('Layer_Version') | ||
25 | 34 | ||
26 | class ProjectManager(models.Manager): | 35 | class ProjectManager(models.Manager): |
27 | def create_project(self, name, branch, short_description): | 36 | def create_project(self, name, release): |
28 | prj = self.model(name = name, branch = branch, short_description = short_description) | 37 | prj = self.model(name = name, bitbake_version = release.bitbake_version, release = release) |
29 | prj.save() | 38 | prj.save() |
30 | 39 | ||
31 | # create default variables | 40 | for defaultconf in ToasterSetting.objects.filter(name__startswith="DEFCONF_"): |
32 | ProjectVariable.objects.create(project = prj, name = "MACHINE", value = "qemux86") | 41 | name = defaultconf.name[8:] |
33 | ProjectVariable.objects.create(project = prj, name = "DISTRO", value = "poky") | 42 | ProjectVariable.objects.create( project = prj, |
34 | 43 | name = name, | |
35 | # create default layers | 44 | value = defaultconf.value) |
36 | ProjectLayer.objects.create(project = prj, | 45 | |
37 | name = "meta", | 46 | for layer in map(lambda x: x.layer, ReleaseDefaultLayer.objects.filter(release = release)): |
38 | giturl = "git://git.yoctoproject.org/poky", | 47 | for branches in Branch.objects.filter(name = release.branch): |
39 | commit = branch, | 48 | for lv in Layer_Version.objects.filter(layer = layer, up_branch = branches ): |
40 | dirpath = "meta", | 49 | ProjectLayer.objects.create( project = prj, |
41 | optional = False) | 50 | layercommit = lv, |
42 | 51 | optional = False ) | |
43 | ProjectLayer.objects.create(project = prj, | ||
44 | name = "meta-yocto", | ||
45 | giturl = "git://git.yoctoproject.org/poky", | ||
46 | commit = branch, | ||
47 | dirpath = "meta-yocto", | ||
48 | optional = False) | ||
49 | 52 | ||
50 | return prj | 53 | return prj |
51 | 54 | ||
@@ -57,8 +60,9 @@ class ProjectManager(models.Manager): | |||
57 | 60 | ||
58 | class Project(models.Model): | 61 | class Project(models.Model): |
59 | name = models.CharField(max_length=100) | 62 | name = models.CharField(max_length=100) |
60 | branch = models.CharField(max_length=50) | ||
61 | short_description = models.CharField(max_length=50, blank=True) | 63 | short_description = models.CharField(max_length=50, blank=True) |
64 | bitbake_version = models.ForeignKey('BitbakeVersion') | ||
65 | release = models.ForeignKey("Release") | ||
62 | created = models.DateTimeField(auto_now_add = True) | 66 | created = models.DateTimeField(auto_now_add = True) |
63 | updated = models.DateTimeField(auto_now = True) | 67 | updated = models.DateTimeField(auto_now = True) |
64 | # This is a horrible hack; since Toaster has no "User" model available when | 68 | # This is a horrible hack; since Toaster has no "User" model available when |
@@ -70,10 +74,16 @@ class Project(models.Model): | |||
70 | 74 | ||
71 | 75 | ||
72 | def schedule_build(self): | 76 | def schedule_build(self): |
73 | from bldcontrol.models import BuildRequest, BRTarget, BRLayer, BRVariable | 77 | from bldcontrol.models import BuildRequest, BRTarget, BRLayer, BRVariable, BRBitbake |
74 | br = BuildRequest.objects.create(project = self) | 78 | br = BuildRequest.objects.create(project = self) |
79 | |||
80 | BRBitbake.objects.create(req = br, | ||
81 | giturl = self.bitbake_version.giturl, | ||
82 | commit = self.bitbake_version.branch, | ||
83 | dirpath = self.bitbake_version.dirpath) | ||
84 | |||
75 | for l in self.projectlayer_set.all(): | 85 | for l in self.projectlayer_set.all(): |
76 | BRLayer.objects.create(req = br, name = l.name, giturl = l.giturl, commit = l.commit, dirpath = l.dirpath) | 86 | BRLayer.objects.create(req = br, name = l.layercommit.layer.name, giturl = l.layercommit.layer.vcs_url, commit = l.layercommit.commit, dirpath = l.layercommit.dirpath) |
77 | for t in self.projecttarget_set.all(): | 87 | for t in self.projecttarget_set.all(): |
78 | BRTarget.objects.create(req = br, target = t.target, task = t.task) | 88 | BRTarget.objects.create(req = br, target = t.target, task = t.task) |
79 | for v in self.projectvariable_set.all(): | 89 | for v in self.projectvariable_set.all(): |
@@ -83,7 +93,6 @@ class Project(models.Model): | |||
83 | br.save() | 93 | br.save() |
84 | return br | 94 | return br |
85 | 95 | ||
86 | |||
87 | class Build(models.Model): | 96 | class Build(models.Model): |
88 | SUCCEEDED = 0 | 97 | SUCCEEDED = 0 |
89 | FAILED = 1 | 98 | FAILED = 1 |
@@ -359,8 +368,13 @@ class Package_File(models.Model): | |||
359 | 368 | ||
360 | class Recipe(models.Model): | 369 | class Recipe(models.Model): |
361 | search_allowed_fields = ['name', 'version', 'file_path', 'section', 'license', 'layer_version__layer__name', 'layer_version__branch', 'layer_version__commit', 'layer_version__layer__local_path'] | 370 | search_allowed_fields = ['name', 'version', 'file_path', 'section', 'license', 'layer_version__layer__name', 'layer_version__branch', 'layer_version__commit', 'layer_version__layer__local_path'] |
362 | name = models.CharField(max_length=100, blank=True) | 371 | |
363 | version = models.CharField(max_length=100, blank=True) | 372 | layer_source = models.ForeignKey('LayerSource', default = None, null = True) # from where did we get this recipe |
373 | up_id = models.IntegerField(null = True, default = None) # id of entry in the source | ||
374 | up_date = models.DateTimeField(null = True, default = None) | ||
375 | |||
376 | name = models.CharField(max_length=100, blank=True) # pn | ||
377 | version = models.CharField(max_length=100, blank=True) # pv | ||
364 | layer_version = models.ForeignKey('Layer_Version', related_name='recipe_layer_version') | 378 | layer_version = models.ForeignKey('Layer_Version', related_name='recipe_layer_version') |
365 | summary = models.CharField(max_length=100, blank=True) | 379 | summary = models.CharField(max_length=100, blank=True) |
366 | description = models.TextField(blank=True) | 380 | description = models.TextField(blank=True) |
@@ -370,6 +384,9 @@ class Recipe(models.Model): | |||
370 | bugtracker = models.URLField(blank=True) | 384 | bugtracker = models.URLField(blank=True) |
371 | file_path = models.FilePathField(max_length=255) | 385 | file_path = models.FilePathField(max_length=255) |
372 | 386 | ||
387 | def __unicode__(self): | ||
388 | return "Recipe " + self.name + ":" + self.version | ||
389 | |||
373 | class Recipe_DependencyManager(models.Manager): | 390 | class Recipe_DependencyManager(models.Manager): |
374 | use_for_related_fields = True | 391 | use_for_related_fields = True |
375 | 392 | ||
@@ -389,27 +406,311 @@ class Recipe_Dependency(models.Model): | |||
389 | dep_type = models.IntegerField(choices=DEPENDS_TYPE) | 406 | dep_type = models.IntegerField(choices=DEPENDS_TYPE) |
390 | objects = Recipe_DependencyManager() | 407 | objects = Recipe_DependencyManager() |
391 | 408 | ||
392 | class ProjectLayer(models.Model): | ||
393 | project = models.ForeignKey(Project) | ||
394 | name = models.CharField(max_length = 100) | ||
395 | giturl = models.CharField(max_length = 254) | ||
396 | commit = models.CharField(max_length = 254) | ||
397 | dirpath = models.CharField(max_length = 254) | ||
398 | optional = models.BooleanField(default = True) | ||
399 | 409 | ||
410 | class Machine(models.Model): | ||
411 | layer_source = models.ForeignKey('LayerSource', default = None, null = True) # from where did we get this machine | ||
412 | up_id = models.IntegerField(null = True, default = None) # id of entry in the source | ||
413 | up_date = models.DateTimeField(null = True, default = None) | ||
414 | |||
415 | layer_version = models.ForeignKey('Layer_Version') | ||
416 | name = models.CharField(max_length=255) | ||
417 | description = models.CharField(max_length=255) | ||
418 | |||
419 | def __unicode__(self): | ||
420 | return "Machine " + self.name + "(" + self.description + ")" | ||
421 | |||
422 | class Meta: | ||
423 | unique_together = ("layer_source", "up_id") | ||
424 | |||
425 | |||
426 | from django.db.models.base import ModelBase | ||
427 | |||
428 | class InheritanceMetaclass(ModelBase): | ||
429 | def __call__(cls, *args, **kwargs): | ||
430 | obj = super(InheritanceMetaclass, cls).__call__(*args, **kwargs) | ||
431 | return obj.get_object() | ||
432 | |||
433 | |||
434 | class LayerSource(models.Model): | ||
435 | __metaclass__ = InheritanceMetaclass | ||
436 | |||
437 | class Meta: | ||
438 | unique_together = (('sourcetype', 'apiurl'), ) | ||
439 | |||
440 | TYPE_LOCAL = 0 | ||
441 | TYPE_LAYERINDEX = 1 | ||
442 | SOURCE_TYPE = ( | ||
443 | (TYPE_LOCAL, "local"), | ||
444 | (TYPE_LAYERINDEX, "layerindex"), | ||
445 | ) | ||
446 | |||
447 | name = models.CharField(max_length=63) | ||
448 | sourcetype = models.IntegerField(choices=SOURCE_TYPE) | ||
449 | apiurl = models.CharField(max_length=255, null=True, default=None) | ||
450 | |||
451 | def save(self, *args, **kwargs): | ||
452 | if isinstance(self, LocalLayerSource): | ||
453 | self.sourcetype = LayerSource.TYPE_LOCAL | ||
454 | elif isinstance(self, LayerIndexLayerSource): | ||
455 | self.sourcetype = LayerSource.TYPE_LAYERINDEX | ||
456 | elif self.sourcetype == None: | ||
457 | raise Exception("Invalid LayerSource type") | ||
458 | return super(LayerSource, self).save(*args, **kwargs) | ||
459 | |||
460 | def get_object(self): | ||
461 | if self.sourcetype is not None: | ||
462 | if self.sourcetype == LayerSource.TYPE_LOCAL: | ||
463 | self.__class__ = LocalLayerSource | ||
464 | if self.sourcetype == LayerSource.TYPE_LAYERINDEX: | ||
465 | self.__class__ = LayerIndexLayerSource | ||
466 | return self | ||
467 | |||
468 | return "LS " + self.sourcetype + " " + self.name | ||
469 | |||
470 | |||
471 | class LocalLayerSource(LayerSource): | ||
472 | class Meta(LayerSource._meta.__class__): | ||
473 | proxy = True | ||
474 | |||
475 | def __init__(self, *args, **kwargs): | ||
476 | super(LocalLayerSource, self).__init__(args, kwargs) | ||
477 | self.sourcetype = LayerSource.TYPE_LOCAL | ||
478 | |||
479 | def update(self): | ||
480 | ''' | ||
481 | Fetches layer, recipe and machine information from local repository | ||
482 | ''' | ||
483 | pass | ||
484 | |||
485 | class LayerIndexLayerSource(LayerSource): | ||
486 | class Meta(LayerSource._meta.__class__): | ||
487 | proxy = True | ||
488 | |||
489 | def __init__(self, *args, **kwargs): | ||
490 | super(LayerIndexLayerSource, self).__init__(args, kwargs) | ||
491 | self.sourcetype = LayerSource.TYPE_LAYERINDEX | ||
492 | |||
493 | def update(self): | ||
494 | ''' | ||
495 | Fetches layer, recipe and machine information from remote repository | ||
496 | ''' | ||
497 | assert self.apiurl is not None | ||
498 | |||
499 | def _get_json_response(apiurl = self.apiurl): | ||
500 | import httplib, urlparse, json | ||
501 | parsedurl = urlparse.urlparse(apiurl) | ||
502 | (host, port) = parsedurl.netloc.split(":") | ||
503 | if port is None: | ||
504 | port = 80 | ||
505 | else: | ||
506 | port = int(port) | ||
507 | #print "-- connect to: http://%s:%s%s?%s" % (host, port, parsedurl.path, parsedurl.query) | ||
508 | conn = httplib.HTTPConnection(host, port) | ||
509 | conn.request("GET", parsedurl.path + "?" + parsedurl.query) | ||
510 | r = conn.getresponse() | ||
511 | if r.status != 200: | ||
512 | raise Exception("Failed to read " + parsedurl.path + ": %d %s" % (r.status, r.reason)) | ||
513 | return json.loads(r.read()) | ||
514 | |||
515 | # verify we can get the basic api | ||
516 | try: | ||
517 | apilinks = _get_json_response() | ||
518 | except: | ||
519 | print "EE: could not connect to %s, skipping update" % self.apiurl | ||
520 | return | ||
521 | |||
522 | # update branches; only those that we already have names listed in the database | ||
523 | whitelist_branch_names = self.branchnames.split(",") | ||
524 | |||
525 | branches_info = _get_json_response(apilinks['branches'] | ||
526 | + "?filter=name:%s" % "OR".join(whitelist_branch_names)) | ||
527 | for bi in branches_info: | ||
528 | try: | ||
529 | b = Branch.objects.get(layer_source = self, name = bi['name']) | ||
530 | b.up_id = bi['id'] | ||
531 | b.up_date = bi['updated'] | ||
532 | b.name = bi['name'] | ||
533 | b.bitbake_branch = bi['bitbake_branch'] | ||
534 | b.short_description = bi['short_description'] | ||
535 | b.save() | ||
536 | except Branch.DoesNotExist: | ||
537 | b = Branch.objects.create( | ||
538 | layer_source = self, | ||
539 | up_id = bi['id'], | ||
540 | up_date = bi['updated'], | ||
541 | name = bi['name'], | ||
542 | bitbake_branch = bi['bitbake_branch'], | ||
543 | short_description = bi['short_description'] | ||
544 | ) | ||
545 | |||
546 | # update layers | ||
547 | layers_info = _get_json_response(apilinks['layerItems']) | ||
548 | for li in layers_info: | ||
549 | try: | ||
550 | l = Layer.objects.get(layer_source = self, | ||
551 | up_id = li['id']) | ||
552 | l.update( | ||
553 | up_date = li['updated'], | ||
554 | name = li['name'], | ||
555 | vcs_url = li['vcs_url'], | ||
556 | vcs_web_file_base_url = li['vcs_url'], | ||
557 | summary = li['summary'], | ||
558 | description = li['description']) | ||
559 | except Layer.DoesNotExist: | ||
560 | Layer.objects.create(layer_source = self, | ||
561 | up_id = li['id'], | ||
562 | up_date = li['updated'], | ||
563 | name = li['name'], | ||
564 | vcs_url = li['vcs_url'], | ||
565 | vcs_web_file_base_url = li['vcs_url'], | ||
566 | summary = li['summary'], | ||
567 | description = li['description'] | ||
568 | ) | ||
569 | |||
570 | # update layerbranches/layer_versions | ||
571 | layerbranches_info = _get_json_response(apilinks['layerBranches'] | ||
572 | + "?filter=branch:%s" % "OR".join(map(lambda x: str(x.up_id), Branch.objects.filter(layer_source = self))) | ||
573 | ) | ||
574 | for lbi in layerbranches_info: | ||
575 | Layer_Version.objects.get_or_create(layer_source = self, | ||
576 | up_id = lbi['id'], | ||
577 | up_date = lbi['updated'], | ||
578 | layer = Layer.objects.get(layer_source = self, up_id = lbi['layer']), | ||
579 | up_branch = Branch.objects.get(layer_source = self, up_id = lbi['branch']), | ||
580 | branch = lbi['actual_branch'], | ||
581 | commit = lbi['vcs_last_rev'], | ||
582 | dirpath = lbi['vcs_subdir']) | ||
583 | |||
584 | # update machines | ||
585 | machines_info = _get_json_response(apilinks['machines'] | ||
586 | + "?filter=layerbranch:%s" % "OR".join(map(lambda x: str(x.up_id), Layer_Version.objects.filter(layer_source = self))) | ||
587 | ) | ||
588 | for mi in machines_info: | ||
589 | Machine.objects.get_or_create(layer_source = self, | ||
590 | up_id = mi['id'], | ||
591 | up_date = mi['updated'], | ||
592 | layer_version = Layer_Version.objects.get(layer_source = self, up_id = mi['layerbranch']), | ||
593 | name = mi['name'], | ||
594 | description = mi['description']) | ||
595 | |||
596 | # update recipes; paginate by layer version / layer branch | ||
597 | recipes_info = _get_json_response(apilinks['recipes'] | ||
598 | + "?filter=layerbranch:%s" % "OR".join(map(lambda x: str(x.up_id), Layer_Version.objects.filter(layer_source = self))) | ||
599 | ) | ||
600 | for ri in recipes_info: | ||
601 | Recipe.objects.get_or_create(layer_source = self, | ||
602 | up_id = ri['id'], | ||
603 | up_date = ri['updated'], | ||
604 | layer_version = Layer_Version.objects.get(layer_source = self, up_id = mi['layerbranch']), | ||
605 | |||
606 | name = ri['pn'], | ||
607 | version = ri['pv'], | ||
608 | summary = ri['summary'], | ||
609 | description = ri['description'], | ||
610 | section = ri['section'], | ||
611 | license = ri['license'], | ||
612 | homepage = ri['homepage'], | ||
613 | bugtracker = ri['bugtracker'], | ||
614 | file_path = ri['filepath'] + ri['filename'] | ||
615 | ) | ||
616 | |||
617 | pass | ||
618 | |||
619 | class BitbakeVersion(models.Model): | ||
620 | name = models.CharField(max_length=32, unique = True) | ||
621 | giturl = models.URLField() | ||
622 | branch = models.CharField(max_length=32) | ||
623 | dirpath = models.CharField(max_length=255) | ||
624 | |||
625 | |||
626 | class Release(models.Model): | ||
627 | name = models.CharField(max_length=32, unique = True) | ||
628 | description = models.CharField(max_length=255) | ||
629 | bitbake_version = models.ForeignKey(BitbakeVersion) | ||
630 | branch = models.CharField(max_length=32) | ||
631 | |||
632 | |||
633 | class ReleaseDefaultLayer(models.Model): | ||
634 | release = models.ForeignKey(Release) | ||
635 | layer = models.ForeignKey('Layer') | ||
636 | |||
637 | |||
638 | # Branch class is synced with layerindex.Branch, branches can only come from remote layer indexes | ||
639 | class Branch(models.Model): | ||
640 | layer_source = models.ForeignKey('LayerSource', null = True, default = True) | ||
641 | up_id = models.IntegerField(null = True, default = None) # id of branch in the source | ||
642 | up_date = models.DateTimeField(null = True, default = None) | ||
643 | |||
644 | name = models.CharField(max_length=50) | ||
645 | bitbake_branch = models.CharField(max_length=50, blank=True) | ||
646 | short_description = models.CharField(max_length=50, blank=True) | ||
647 | |||
648 | class Meta: | ||
649 | verbose_name_plural = "Branches" | ||
650 | unique_together = (('layer_source', 'name'),('layer_source', 'up_id')) | ||
651 | |||
652 | def __unicode__(self): | ||
653 | return self.name | ||
654 | |||
655 | |||
656 | # Layer class synced with layerindex.LayerItem | ||
400 | class Layer(models.Model): | 657 | class Layer(models.Model): |
658 | layer_source = models.ForeignKey(LayerSource, null = True, default = None) # from where did we got this layer | ||
659 | up_id = models.IntegerField(null = True, default = None) # id of layer in the remote source | ||
660 | up_date = models.DateTimeField(null = True, default = None) | ||
661 | |||
401 | name = models.CharField(max_length=100) | 662 | name = models.CharField(max_length=100) |
402 | local_path = models.FilePathField(max_length=255) | 663 | local_path = models.FilePathField(max_length=255, null = True, default = None) |
403 | layer_index_url = models.URLField() | 664 | layer_index_url = models.URLField() |
665 | vcs_url = models.URLField(default = None, null = True) | ||
666 | vcs_web_file_base_url = models.URLField(null = True, default = None) | ||
667 | |||
668 | summary = models.CharField(max_length=200, help_text='One-line description of the layer', null = True, default = None) | ||
669 | description = models.TextField(null = True, default = None) | ||
670 | |||
671 | def __unicode__(self): | ||
672 | return "L " + self.name | ||
673 | |||
674 | class Meta: | ||
675 | unique_together = (("layer_source", "up_id"), ("layer_source", "name")) | ||
404 | 676 | ||
405 | 677 | ||
678 | # LayerCommit class is synced with layerindex.LayerBranch | ||
406 | class Layer_Version(models.Model): | 679 | class Layer_Version(models.Model): |
407 | build = models.ForeignKey(Build, related_name='layer_version_build') | 680 | search_allowed_fields = ["layer__name", "layer__summary",] |
681 | build = models.ForeignKey(Build, related_name='layer_version_build', default = None, null = True) | ||
408 | layer = models.ForeignKey(Layer, related_name='layer_version_layer') | 682 | layer = models.ForeignKey(Layer, related_name='layer_version_layer') |
409 | branch = models.CharField(max_length=50) | ||
410 | commit = models.CharField(max_length=100) | ||
411 | priority = models.IntegerField() | ||
412 | 683 | ||
684 | layer_source = models.ForeignKey(LayerSource, null = True, default = None) # from where did we get this Layer Version | ||
685 | up_id = models.IntegerField(null = True, default = None) # id of layerbranch in the remote source | ||
686 | up_date = models.DateTimeField(null = True, default = None) | ||
687 | up_branch = models.ForeignKey(Branch, null = True, default = None) | ||
688 | |||
689 | branch = models.CharField(max_length=80) # LayerBranch.actual_branch | ||
690 | commit = models.CharField(max_length=100) # LayerBranch.vcs_last_rev | ||
691 | dirpath = models.CharField(max_length=255, null = True, default = None) # LayerBranch.vcs_subdir | ||
692 | priority = models.IntegerField(default = 0) # if -1, this is a default layer | ||
693 | |||
694 | def __unicode__(self): | ||
695 | return "LV " + str(self.layer) + " " + self.commit | ||
696 | |||
697 | class Meta: | ||
698 | unique_together = ("layer_source", "up_id") | ||
699 | |||
700 | class LayerVersionDependency(models.Model): | ||
701 | layer_source = models.ForeignKey(LayerSource, null = True, default = None) # from where did we got this layer | ||
702 | up_id = models.IntegerField(null = True, default = None) # id of layerbranch in the remote source | ||
703 | |||
704 | layer_version = models.ForeignKey(Layer_Version, related_name="dependencies") | ||
705 | depends_on = models.ForeignKey(Layer_Version, related_name="dependees") | ||
706 | |||
707 | class Meta: | ||
708 | unique_together = ("layer_source", "up_id") | ||
709 | |||
710 | class ProjectLayer(models.Model): | ||
711 | project = models.ForeignKey(Project) | ||
712 | layercommit = models.ForeignKey(Layer_Version, null=True) | ||
713 | optional = models.BooleanField(default = True) | ||
413 | 714 | ||
414 | class ProjectVariable(models.Model): | 715 | class ProjectVariable(models.Model): |
415 | project = models.ForeignKey(Project) | 716 | project = models.ForeignKey(Project) |