summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2014-11-14 17:07:06 (GMT)
committerRichard Purdie <richard.purdie@linuxfoundation.org>2014-11-21 11:49:23 (GMT)
commit0b6859cdf3a4b66bb8b94361681a5b6b362f93ae (patch)
tree37bf5c650e99b023bd0e0605b63a53cc0ebd0b72
parent5b0616ad7d7c3734f1818a56b631a2d254271678 (diff)
downloadpoky-0b6859cdf3a4b66bb8b94361681a5b6b362f93ae.tar.gz
bitbake: toastergui: layer name correlation
This patch modifies how layers are identified and matched. Layers were primarely organized by the source of layer information, and Releases were separated by both layer git branches and originating source of layer information. This setup prevented mixing layers from different sources for a certain release, which didn't match the way people use Yocto Project / bitbake. This patch brings name-based indentification, where layers with the same name are assumed to be equivalent, in the sense of being able to substitute one another. To facilitate this identification to humans, layers are differentiated by GIT URI instead of layer sources, which was a rather arbitrary abstraction. Additional changes include modification to models in order accomodate for the new data structure, and to config file loading to match the new toasterconf.json layout. (Bitbake rev: 4357200aed522ad56cfd84917f877645b83b6a70) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rwxr-xr-xbitbake/bin/toaster2
-rw-r--r--bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py47
-rw-r--r--bitbake/lib/toaster/bldcontrol/management/commands/loadconf.py29
-rw-r--r--bitbake/lib/toaster/orm/migrations/0017_auto__del_toastersettingdefaultlayer__add_releaselayersourcepriority__.py396
-rw-r--r--bitbake/lib/toaster/orm/models.py115
-rw-r--r--bitbake/lib/toaster/orm/tests.py11
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/projectapp.js2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/layers.html6
-rw-r--r--bitbake/lib/toaster/toastergui/templates/project.html4
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py84
10 files changed, 599 insertions, 97 deletions
diff --git a/bitbake/bin/toaster b/bitbake/bin/toaster
index 75f31d0..7511012 100755
--- a/bitbake/bin/toaster
+++ b/bitbake/bin/toaster
@@ -126,7 +126,6 @@ function notify_chldexit() {
126} 126}
127 127
128 128
129
130# Verify prerequisites 129# Verify prerequisites
131 130
132if ! echo "import django; print (1,) == django.VERSION[0:1] and django.VERSION[1:2][0] in (5,6)" | python 2>/dev/null | grep True >/dev/null; then 131if ! echo "import django; print (1,) == django.VERSION[0:1] and django.VERSION[1:2][0] in (5,6)" | python 2>/dev/null | grep True >/dev/null; then
@@ -139,6 +138,7 @@ if ! echo "import south; print [0,8,4] == map(int,south.__version__.split(\".\"
139 return 2 138 return 2
140fi 139fi
141 140
141
142# read command line parameters 142# read command line parameters
143 143
144BBBASEDIR=`dirname ${BASH_SOURCE}`/.. 144BBBASEDIR=`dirname ${BASH_SOURCE}`/..
diff --git a/bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py b/bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py
index 56e4e1b..cd604eb 100644
--- a/bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py
+++ b/bitbake/lib/toaster/bldcontrol/management/commands/checksettings.py
@@ -34,6 +34,22 @@ class Command(NoArgsCommand):
34 return ret 34 return ret
35 return None 35 return None
36 36
37 def _recursive_list_directories(self, startdirectory, level = 0):
38 if level < 0:
39 return []
40 dirs = []
41 try:
42 for i in os.listdir(startdirectory):
43 j = os.path.join(startdirectory, i)
44 if os.path.isdir(j):
45 dirs.append(j)
46 except OSError:
47 pass
48 for j in dirs:
49 dirs = dirs + self._recursive_list_directories(j, level - 1)
50 return dirs
51
52
37 def _get_suggested_sourcedir(self, be): 53 def _get_suggested_sourcedir(self, be):
38 if be.betype != BuildEnvironment.TYPE_LOCAL: 54 if be.betype != BuildEnvironment.TYPE_LOCAL:
39 return "" 55 return ""
@@ -67,7 +83,6 @@ class Command(NoArgsCommand):
67 print("Verifying the Build Environment type %s id %d." % (be.get_betype_display(), be.pk)) 83 print("Verifying the Build Environment type %s id %d." % (be.get_betype_display(), be.pk))
68 if len(be.sourcedir) == 0: 84 if len(be.sourcedir) == 0:
69 suggesteddir = self._get_suggested_sourcedir(be) 85 suggesteddir = self._get_suggested_sourcedir(be)
70 homesourcedir = suggesteddir
71 be.sourcedir = raw_input(" -- Layer sources checkout directory may not be empty [guessed \"%s\"]:" % suggesteddir) 86 be.sourcedir = raw_input(" -- Layer sources checkout directory may not be empty [guessed \"%s\"]:" % suggesteddir)
72 if len(be.sourcedir) == 0 and len(suggesteddir) > 0: 87 if len(be.sourcedir) == 0 and len(suggesteddir) > 0:
73 be.sourcedir = suggesteddir 88 be.sourcedir = suggesteddir
@@ -94,17 +109,25 @@ class Command(NoArgsCommand):
94 be.save() 109 be.save()
95 110
96 if is_changed and be.betype == BuildEnvironment.TYPE_LOCAL: 111 if is_changed and be.betype == BuildEnvironment.TYPE_LOCAL:
97 baselayerdir = DN(DN(self._find_first_path_for_file(homesourcedir, "toasterconf.json", 3))) 112 for dirname in self._recursive_list_directories(be.sourcedir,2):
98 if baselayerdir: 113 if os.path.exists(os.path.join(dirname, ".templateconf")):
99 i = raw_input(" -- Do you want to import basic layer configuration from \"%s\" ? (y/N):" % baselayerdir) 114 import subprocess
100 if len(i) and i.upper()[0] == 'Y': 115 conffilepath, error = subprocess.Popen('bash -c ". '+os.path.join(dirname, ".templateconf")+'; echo \"\$TEMPLATECONF\""', shell=True, stdout=subprocess.PIPE).communicate()
101 from loadconf import Command as LoadConfigCommand 116 conffilepath = os.path.join(conffilepath.strip(), "toasterconf.json")
102 LoadConfigCommand()._import_layer_config(os.path.join(baselayerdir, "meta/conf/toasterconf.json")) 117 candidatefilepath = os.path.join(dirname, conffilepath)
103 # we run lsupdates after config update 118 if os.path.exists(candidatefilepath):
104 print "Updating information from the layer source, please wait." 119 i = raw_input(" -- Do you want to import basic layer configuration from \"%s\" ? (y/N):" % candidatefilepath)
105 from django.core.management import call_command 120 if len(i) and i.upper()[0] == 'Y':
106 call_command("lsupdates") 121 from loadconf import Command as LoadConfigCommand
107 pass 122
123 LoadConfigCommand()._import_layer_config(candidatefilepath)
124 # we run lsupdates after config update
125 print "Layer configuration imported. Updating information from the layer source, please wait."
126 from django.core.management import call_command
127 call_command("lsupdates")
128
129 # we don't look for any other config files
130 return is_changed
108 131
109 return is_changed 132 return is_changed
110 133
diff --git a/bitbake/lib/toaster/bldcontrol/management/commands/loadconf.py b/bitbake/lib/toaster/bldcontrol/management/commands/loadconf.py
index c9af487..6e1f97a 100644
--- a/bitbake/lib/toaster/bldcontrol/management/commands/loadconf.py
+++ b/bitbake/lib/toaster/bldcontrol/management/commands/loadconf.py
@@ -1,6 +1,6 @@
1from django.core.management.base import BaseCommand, CommandError 1from django.core.management.base import BaseCommand, CommandError
2from orm.models import LayerSource, ToasterSetting, Branch, Layer, Layer_Version 2from orm.models import LayerSource, ToasterSetting, Branch, Layer, Layer_Version
3from orm.models import BitbakeVersion, Release, ReleaseDefaultLayer 3from orm.models import BitbakeVersion, Release, ReleaseDefaultLayer, ReleaseLayerSourcePriority
4import os 4import os
5 5
6from checksettings import DN 6from checksettings import DN
@@ -71,17 +71,23 @@ class Command(BaseCommand):
71 assert 'name' in lsi 71 assert 'name' in lsi
72 assert 'branches' in lsi 72 assert 'branches' in lsi
73 73
74 if lsi['sourcetype'] == LayerSource.TYPE_LAYERINDEX or lsi['apiurl'].startswith("/"): 74 def _get_id_for_sourcetype(s):
75 for i in LayerSource.SOURCE_TYPE:
76 if s == i[1]:
77 return i[0]
78 raise Exception("Could not find definition for sourcetype " + s)
79
80 if _get_id_for_sourcetype(lsi['sourcetype']) == LayerSource.TYPE_LAYERINDEX or lsi['apiurl'].startswith("/"):
75 apiurl = lsi['apiurl'] 81 apiurl = lsi['apiurl']
76 else: 82 else:
77 apiurl = self._reduce_canon_path(os.path.join(DN(filepath), lsi['apiurl'])) 83 apiurl = self._reduce_canon_path(os.path.join(DN(filepath), lsi['apiurl']))
78 84
79 try: 85 try:
80 ls = LayerSource.objects.get(sourcetype = lsi['sourcetype'], apiurl = apiurl) 86 ls = LayerSource.objects.get(sourcetype = _get_id_for_sourcetype(lsi['sourcetype']), apiurl = apiurl)
81 except LayerSource.DoesNotExist: 87 except LayerSource.DoesNotExist:
82 ls = LayerSource.objects.create( 88 ls = LayerSource.objects.create(
83 name = lsi['name'], 89 name = lsi['name'],
84 sourcetype = lsi['sourcetype'], 90 sourcetype = _get_id_for_sourcetype(lsi['sourcetype']),
85 apiurl = apiurl 91 apiurl = apiurl
86 ) 92 )
87 93
@@ -121,17 +127,20 @@ class Command(BaseCommand):
121 bvo = BitbakeVersion.objects.get(name = ri['bitbake']) 127 bvo = BitbakeVersion.objects.get(name = ri['bitbake'])
122 assert bvo is not None 128 assert bvo is not None
123 129
124 ro, created = Release.objects.get_or_create(name = ri['name'], bitbake_version = bvo, branch = Branch.objects.get( layer_source__name = ri['layersource'], name=ri['branch'])) 130 ro, created = Release.objects.get_or_create(name = ri['name'], bitbake_version = bvo, branch_name = ri['branch'])
125 ro.description = ri['description'] 131 ro.description = ri['description']
126 ro.helptext = ri['helptext'] 132 ro.helptext = ri['helptext']
127 ro.save() 133 ro.save()
128 134
135 # save layer source priority for release
136 for ls_name in ri['layersourcepriority'].keys():
137 rlspo, created = ReleaseLayerSourcePriority.objects.get_or_create(release = ro, layer_source = LayerSource.objects.get(name=ls_name))
138 rlspo.priority = ri['layersourcepriority'][ls_name]
139 rlspo.save()
140
129 for dli in ri['defaultlayers']: 141 for dli in ri['defaultlayers']:
130 layer, created = Layer.objects.get_or_create( 142 # find layers with the same name
131 layer_source = LayerSource.objects.get(name = ri['layersource']), 143 ReleaseDefaultLayer.objects.get_or_create( release = ro, layer_name = dli)
132 name = dli
133 )
134 ReleaseDefaultLayer.objects.get_or_create( release = ro, layer = layer)
135 144
136 # set default release 145 # set default release
137 if ToasterSetting.objects.filter(name = "DEFAULT_RELEASE").count() > 0: 146 if ToasterSetting.objects.filter(name = "DEFAULT_RELEASE").count() > 0:
diff --git a/bitbake/lib/toaster/orm/migrations/0017_auto__del_toastersettingdefaultlayer__add_releaselayersourcepriority__.py b/bitbake/lib/toaster/orm/migrations/0017_auto__del_toastersettingdefaultlayer__add_releaselayersourcepriority__.py
new file mode 100644
index 0000000..6685b55
--- /dev/null
+++ b/bitbake/lib/toaster/orm/migrations/0017_auto__del_toastersettingdefaultlayer__add_releaselayersourcepriority__.py
@@ -0,0 +1,396 @@
1# -*- coding: utf-8 -*-
2from south.utils import datetime_utils as datetime
3from south.db import db
4from south.v2 import SchemaMigration
5from django.db import models
6
7
8class Migration(SchemaMigration):
9
10 def forwards(self, orm):
11 # Deleting model 'ToasterSettingDefaultLayer'
12 db.delete_table(u'orm_toastersettingdefaultlayer')
13
14 # Adding model 'ReleaseLayerSourcePriority'
15 db.create_table(u'orm_releaselayersourcepriority', (
16 (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
17 ('release', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['orm.Release'])),
18 ('layer_source', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['orm.LayerSource'])),
19 ('priority', self.gf('django.db.models.fields.IntegerField')(default=0)),
20 ))
21 db.send_create_signal(u'orm', ['ReleaseLayerSourcePriority'])
22
23 # Adding unique constraint on 'ReleaseLayerSourcePriority', fields ['release', 'layer_source']
24 db.create_unique(u'orm_releaselayersourcepriority', ['release_id', 'layer_source_id'])
25
26 # Deleting field 'Release.branch'
27 db.delete_column(u'orm_release', 'branch_id')
28
29 # Adding field 'Release.branch_name'
30 db.add_column(u'orm_release', 'branch_name',
31 self.gf('django.db.models.fields.CharField')(default='', max_length=50),
32 keep_default=False)
33
34 # Adding unique constraint on 'LayerSource', fields ['name']
35 db.create_unique(u'orm_layersource', ['name'])
36
37 # Deleting field 'ReleaseDefaultLayer.layer'
38 db.delete_column(u'orm_releasedefaultlayer', 'layer_id')
39
40 # Adding field 'ReleaseDefaultLayer.layer_name'
41 db.add_column(u'orm_releasedefaultlayer', 'layer_name',
42 self.gf('django.db.models.fields.CharField')(default='', max_length=100),
43 keep_default=False)
44
45
46 def backwards(self, orm):
47 # Removing unique constraint on 'LayerSource', fields ['name']
48 db.delete_unique(u'orm_layersource', ['name'])
49
50 # Removing unique constraint on 'ReleaseLayerSourcePriority', fields ['release', 'layer_source']
51 db.delete_unique(u'orm_releaselayersourcepriority', ['release_id', 'layer_source_id'])
52
53 # Adding model 'ToasterSettingDefaultLayer'
54 db.create_table(u'orm_toastersettingdefaultlayer', (
55 (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
56 ('layer_version', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['orm.Layer_Version'])),
57 ))
58 db.send_create_signal(u'orm', ['ToasterSettingDefaultLayer'])
59
60 # Deleting model 'ReleaseLayerSourcePriority'
61 db.delete_table(u'orm_releaselayersourcepriority')
62
63
64 # User chose to not deal with backwards NULL issues for 'Release.branch'
65 raise RuntimeError("Cannot reverse this migration. 'Release.branch' and its values cannot be restored.")
66
67 # The following code is provided here to aid in writing a correct migration # Adding field 'Release.branch'
68 db.add_column(u'orm_release', 'branch',
69 self.gf('django.db.models.fields.related.ForeignKey')(to=orm['orm.Branch']),
70 keep_default=False)
71
72 # Deleting field 'Release.branch_name'
73 db.delete_column(u'orm_release', 'branch_name')
74
75
76 # User chose to not deal with backwards NULL issues for 'ReleaseDefaultLayer.layer'
77 raise RuntimeError("Cannot reverse this migration. 'ReleaseDefaultLayer.layer' and its values cannot be restored.")
78
79 # The following code is provided here to aid in writing a correct migration # Adding field 'ReleaseDefaultLayer.layer'
80 db.add_column(u'orm_releasedefaultlayer', 'layer',
81 self.gf('django.db.models.fields.related.ForeignKey')(to=orm['orm.Layer']),
82 keep_default=False)
83
84 # Deleting field 'ReleaseDefaultLayer.layer_name'
85 db.delete_column(u'orm_releasedefaultlayer', 'layer_name')
86
87
88 models = {
89 u'orm.bitbakeversion': {
90 'Meta': {'object_name': 'BitbakeVersion'},
91 'branch': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
92 'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
93 'giturl': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
94 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
95 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'})
96 },
97 u'orm.branch': {
98 'Meta': {'unique_together': "(('layer_source', 'name'), ('layer_source', 'up_id'))", 'object_name': 'Branch'},
99 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
100 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'True', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
101 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
102 'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
103 'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
104 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
105 },
106 u'orm.build': {
107 'Meta': {'object_name': 'Build'},
108 'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
109 'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
110 'completed_on': ('django.db.models.fields.DateTimeField', [], {}),
111 'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
112 'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
113 'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
114 'errors_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
115 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
116 'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
117 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}),
118 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']", 'null': 'True'}),
119 'started_on': ('django.db.models.fields.DateTimeField', [], {}),
120 'timespent': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
121 'warnings_no': ('django.db.models.fields.IntegerField', [], {'default': '0'})
122 },
123 u'orm.helptext': {
124 'Meta': {'object_name': 'HelpText'},
125 'area': ('django.db.models.fields.IntegerField', [], {}),
126 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'helptext_build'", 'to': u"orm['orm.Build']"}),
127 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
128 'key': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
129 'text': ('django.db.models.fields.TextField', [], {})
130 },
131 u'orm.layer': {
132 'Meta': {'unique_together': "(('layer_source', 'up_id'), ('layer_source', 'name'))", 'object_name': 'Layer'},
133 'description': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True'}),
134 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
135 'layer_index_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
136 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
137 'local_path': ('django.db.models.fields.FilePathField', [], {'default': 'None', 'max_length': '255', 'null': 'True'}),
138 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
139 'summary': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True'}),
140 'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
141 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'}),
142 'vcs_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'}),
143 'vcs_web_file_base_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'}),
144 'vcs_web_tree_base_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'}),
145 'vcs_web_url': ('django.db.models.fields.URLField', [], {'default': 'None', 'max_length': '200', 'null': 'True'})
146 },
147 u'orm.layer_version': {
148 'Meta': {'unique_together': "(('layer_source', 'up_id'),)", 'object_name': 'Layer_Version'},
149 'branch': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
150 'build': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'layer_version_build'", 'null': 'True', 'to': u"orm['orm.Build']"}),
151 'commit': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
152 'dirpath': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True'}),
153 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
154 'layer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'layer_version_layer'", 'to': u"orm['orm.Layer']"}),
155 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
156 'priority': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
157 'up_branch': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.Branch']", 'null': 'True'}),
158 'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
159 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
160 },
161 u'orm.layersource': {
162 'Meta': {'unique_together': "(('sourcetype', 'apiurl'),)", 'object_name': 'LayerSource'},
163 'apiurl': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True'}),
164 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
165 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '63'}),
166 'sourcetype': ('django.db.models.fields.IntegerField', [], {})
167 },
168 u'orm.layerversiondependency': {
169 'Meta': {'unique_together': "(('layer_source', 'up_id'),)", 'object_name': 'LayerVersionDependency'},
170 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'dependees'", 'to': u"orm['orm.Layer_Version']"}),
171 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
172 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
173 'layer_version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'dependencies'", 'to': u"orm['orm.Layer_Version']"}),
174 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
175 },
176 u'orm.logmessage': {
177 'Meta': {'object_name': 'LogMessage'},
178 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}),
179 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
180 'level': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
181 'lineno': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
182 'message': ('django.db.models.fields.CharField', [], {'max_length': '240'}),
183 'pathname': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
184 'task': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Task']", 'null': 'True', 'blank': 'True'})
185 },
186 u'orm.machine': {
187 'Meta': {'unique_together': "(('layer_source', 'up_id'),)", 'object_name': 'Machine'},
188 'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
189 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
190 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
191 'layer_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Layer_Version']"}),
192 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
193 'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
194 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'})
195 },
196 u'orm.package': {
197 'Meta': {'object_name': 'Package'},
198 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}),
199 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
200 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
201 'installed_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}),
202 'installed_size': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
203 'license': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
204 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
205 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Recipe']", 'null': 'True'}),
206 'revision': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
207 'section': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
208 'size': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
209 'summary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
210 'version': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
211 },
212 u'orm.package_dependency': {
213 'Meta': {'object_name': 'Package_Dependency'},
214 'dep_type': ('django.db.models.fields.IntegerField', [], {}),
215 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_dependencies_target'", 'to': u"orm['orm.Package']"}),
216 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
217 'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'package_dependencies_source'", 'to': u"orm['orm.Package']"}),
218 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']", 'null': 'True'})
219 },
220 u'orm.package_file': {
221 'Meta': {'object_name': 'Package_File'},
222 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
223 'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'buildfilelist_package'", 'to': u"orm['orm.Package']"}),
224 'path': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
225 'size': ('django.db.models.fields.IntegerField', [], {})
226 },
227 u'orm.project': {
228 'Meta': {'object_name': 'Project'},
229 'bitbake_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.BitbakeVersion']"}),
230 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
231 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
232 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
233 'release': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Release']"}),
234 'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
235 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
236 'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
237 },
238 u'orm.projectlayer': {
239 'Meta': {'unique_together': "(('project', 'layercommit'),)", 'object_name': 'ProjectLayer'},
240 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
241 'layercommit': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Layer_Version']", 'null': 'True'}),
242 'optional': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
243 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"})
244 },
245 u'orm.projecttarget': {
246 'Meta': {'object_name': 'ProjectTarget'},
247 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
248 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
249 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
250 'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
251 },
252 u'orm.projectvariable': {
253 'Meta': {'object_name': 'ProjectVariable'},
254 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
255 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
256 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
257 'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
258 },
259 u'orm.recipe': {
260 'Meta': {'unique_together': "(('layer_version', 'file_path'),)", 'object_name': 'Recipe'},
261 'bugtracker': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
262 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
263 'file_path': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}),
264 'homepage': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
265 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
266 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['orm.LayerSource']", 'null': 'True'}),
267 'layer_version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'recipe_layer_version'", 'to': u"orm['orm.Layer_Version']"}),
268 'license': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
269 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
270 'section': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
271 'summary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
272 'up_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
273 'up_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'}),
274 'version': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
275 },
276 u'orm.recipe_dependency': {
277 'Meta': {'object_name': 'Recipe_Dependency'},
278 'dep_type': ('django.db.models.fields.IntegerField', [], {}),
279 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'r_dependencies_depends'", 'to': u"orm['orm.Recipe']"}),
280 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
281 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'r_dependencies_recipe'", 'to': u"orm['orm.Recipe']"})
282 },
283 u'orm.release': {
284 'Meta': {'object_name': 'Release'},
285 'bitbake_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.BitbakeVersion']"}),
286 'branch_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50'}),
287 'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
288 'helptext': ('django.db.models.fields.TextField', [], {'null': 'True'}),
289 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
290 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'})
291 },
292 u'orm.releasedefaultlayer': {
293 'Meta': {'object_name': 'ReleaseDefaultLayer'},
294 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
295 'layer_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}),
296 'release': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Release']"})
297 },
298 u'orm.releaselayersourcepriority': {
299 'Meta': {'unique_together': "(('release', 'layer_source'),)", 'object_name': 'ReleaseLayerSourcePriority'},
300 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
301 'layer_source': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.LayerSource']"}),
302 'priority': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
303 'release': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Release']"})
304 },
305 u'orm.target': {
306 'Meta': {'object_name': 'Target'},
307 'build': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Build']"}),
308 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
309 'image_size': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
310 'is_image': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
311 'license_manifest_path': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True'}),
312 'target': ('django.db.models.fields.CharField', [], {'max_length': '100'})
313 },
314 u'orm.target_file': {
315 'Meta': {'object_name': 'Target_File'},
316 'directory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'directory_set'", 'null': 'True', 'to': u"orm['orm.Target_File']"}),
317 'group': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
318 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
319 'inodetype': ('django.db.models.fields.IntegerField', [], {}),
320 'owner': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
321 'path': ('django.db.models.fields.FilePathField', [], {'max_length': '100'}),
322 'permission': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
323 'size': ('django.db.models.fields.IntegerField', [], {}),
324 'sym_target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'symlink_set'", 'null': 'True', 'to': u"orm['orm.Target_File']"}),
325 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']"})
326 },
327 u'orm.target_image_file': {
328 'Meta': {'object_name': 'Target_Image_File'},
329 'file_name': ('django.db.models.fields.FilePathField', [], {'max_length': '254'}),
330 'file_size': ('django.db.models.fields.IntegerField', [], {}),
331 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
332 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']"})
333 },
334 u'orm.target_installed_package': {
335 'Meta': {'object_name': 'Target_Installed_Package'},
336 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
337 'package': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'buildtargetlist_package'", 'to': u"orm['orm.Package']"}),
338 'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Target']"})
339 },
340 u'orm.task': {
341 'Meta': {'ordering': "('order', 'recipe')", 'unique_together': "(('build', 'recipe', 'task_name'),)", 'object_name': 'Task'},
342 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_build'", 'to': u"orm['orm.Build']"}),
343 'cpu_usage': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '6', 'decimal_places': '2'}),
344 'disk_io': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
345 'elapsed_time': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '6', 'decimal_places': '2'}),
346 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
347 'line_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
348 'logfile': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
349 'message': ('django.db.models.fields.CharField', [], {'max_length': '240'}),
350 'order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
351 'outcome': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
352 'path_to_sstate_obj': ('django.db.models.fields.FilePathField', [], {'max_length': '500', 'blank': 'True'}),
353 'recipe': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'build_recipe'", 'to': u"orm['orm.Recipe']"}),
354 'script_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
355 'source_url': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'}),
356 'sstate_checksum': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
357 'sstate_result': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
358 'task_executed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
359 'task_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
360 'work_directory': ('django.db.models.fields.FilePathField', [], {'max_length': '255', 'blank': 'True'})
361 },
362 u'orm.task_dependency': {
363 'Meta': {'object_name': 'Task_Dependency'},
364 'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_dependencies_depends'", 'to': u"orm['orm.Task']"}),
365 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
366 'task': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_dependencies_task'", 'to': u"orm['orm.Task']"})
367 },
368 u'orm.toastersetting': {
369 'Meta': {'object_name': 'ToasterSetting'},
370 'helptext': ('django.db.models.fields.TextField', [], {}),
371 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
372 'name': ('django.db.models.fields.CharField', [], {'max_length': '63'}),
373 'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
374 },
375 u'orm.variable': {
376 'Meta': {'object_name': 'Variable'},
377 'build': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variable_build'", 'to': u"orm['orm.Build']"}),
378 'changed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
379 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
380 'human_readable_name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
381 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
382 'variable_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
383 'variable_value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
384 },
385 u'orm.variablehistory': {
386 'Meta': {'object_name': 'VariableHistory'},
387 'file_name': ('django.db.models.fields.FilePathField', [], {'max_length': '255'}),
388 u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
389 'line_number': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
390 'operation': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
391 'value': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
392 'variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'vhistory'", 'to': u"orm['orm.Variable']"})
393 }
394 }
395
396 complete_apps = ['orm'] \ No newline at end of file
diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py
index d99a4c2..c90e047 100644
--- a/bitbake/lib/toaster/orm/models.py
+++ b/bitbake/lib/toaster/orm/models.py
@@ -21,7 +21,6 @@
21 21
22from django.db import models 22from django.db import models
23from django.db.models import F 23from django.db.models import F
24from django.utils.encoding import python_2_unicode_compatible
25from django.utils import timezone 24from django.utils import timezone
26 25
27 26
@@ -54,9 +53,6 @@ class ToasterSetting(models.Model):
54 def __unicode__(self): 53 def __unicode__(self):
55 return "Setting %s" % self.name 54 return "Setting %s" % self.name
56 55
57class ToasterSettingDefaultLayer(models.Model):
58 layer_version = models.ForeignKey('Layer_Version')
59
60class ProjectManager(models.Manager): 56class ProjectManager(models.Manager):
61 def create_project(self, name, release): 57 def create_project(self, name, release):
62 prj = self.model(name = name, bitbake_version = release.bitbake_version, release = release) 58 prj = self.model(name = name, bitbake_version = release.bitbake_version, release = release)
@@ -68,10 +64,10 @@ class ProjectManager(models.Manager):
68 name = name, 64 name = name,
69 value = defaultconf.value) 65 value = defaultconf.value)
70 66
71 for layer in map(lambda x: x.layer, ReleaseDefaultLayer.objects.filter(release = release)): 67
72 for branches in Branch.objects.filter(name = release.branch): 68 for rdl in release.releasedefaultlayer_set.all():
73 for lv in Layer_Version.objects.filter(layer = layer, up_branch = branches ): 69 lv = Layer_Version.objects.filter(layer__name = rdl.layer_name, up_branch__name = release.branch_name)[0].get_equivalents_wpriority(prj)[0]
74 ProjectLayer.objects.create( project = prj, 70 ProjectLayer.objects.create( project = prj,
75 layercommit = lv, 71 layercommit = lv,
76 optional = False ) 72 optional = False )
77 73
@@ -84,6 +80,7 @@ class ProjectManager(models.Manager):
84 raise Exception("Invalid call to Project.objects.get_or_create. Use Project.objects.create_project() to create a project") 80 raise Exception("Invalid call to Project.objects.get_or_create. Use Project.objects.create_project() to create a project")
85 81
86class Project(models.Model): 82class Project(models.Model):
83 search_allowed_fields = ['name', 'short_description', 'release__name', 'release__branch_name']
87 name = models.CharField(max_length=100) 84 name = models.CharField(max_length=100)
88 short_description = models.CharField(max_length=50, blank=True) 85 short_description = models.CharField(max_length=50, blank=True)
89 bitbake_version = models.ForeignKey('BitbakeVersion') 86 bitbake_version = models.ForeignKey('BitbakeVersion')
@@ -97,6 +94,8 @@ class Project(models.Model):
97 user_id = models.IntegerField(null = True) 94 user_id = models.IntegerField(null = True)
98 objects = ProjectManager() 95 objects = ProjectManager()
99 96
97 def __unicode__(self):
98 return "%s (%s, %s)" % (self.name, self.release, self.bitbake_version)
100 99
101 def schedule_build(self): 100 def schedule_build(self):
102 from bldcontrol.models import BuildRequest, BRTarget, BRLayer, BRVariable, BRBitbake 101 from bldcontrol.models import BuildRequest, BRTarget, BRLayer, BRVariable, BRBitbake
@@ -184,7 +183,6 @@ class ProjectTarget(models.Model):
184 target = models.CharField(max_length=100) 183 target = models.CharField(max_length=100)
185 task = models.CharField(max_length=100, null=True) 184 task = models.CharField(max_length=100, null=True)
186 185
187@python_2_unicode_compatible
188class Target(models.Model): 186class Target(models.Model):
189 search_allowed_fields = ['target', 'file_name'] 187 search_allowed_fields = ['target', 'file_name']
190 build = models.ForeignKey(Build) 188 build = models.ForeignKey(Build)
@@ -196,7 +194,7 @@ class Target(models.Model):
196 def package_count(self): 194 def package_count(self):
197 return Target_Installed_Package.objects.filter(target_id__exact=self.id).count() 195 return Target_Installed_Package.objects.filter(target_id__exact=self.id).count()
198 196
199 def __str__(self): 197 def __unicode__(self):
200 return self.target 198 return self.target
201 199
202class Target_Image_File(models.Model): 200class Target_Image_File(models.Model):
@@ -391,10 +389,10 @@ class Package_Dependency(models.Model):
391 (TYPE_RREPLACES, "replaces"), 389 (TYPE_RREPLACES, "replaces"),
392 (TYPE_RCONFLICTS, "conflicts"), 390 (TYPE_RCONFLICTS, "conflicts"),
393 ) 391 )
394 ''' Indexed by dep_type, in view order, key for short name and help 392 """ Indexed by dep_type, in view order, key for short name and help
395 description which when viewed will be printf'd with the 393 description which when viewed will be printf'd with the
396 package name. 394 package name.
397 ''' 395 """
398 DEPENDS_DICT = { 396 DEPENDS_DICT = {
399 TYPE_RDEPENDS : ("depends", "%s is required to run %s"), 397 TYPE_RDEPENDS : ("depends", "%s is required to run %s"),
400 TYPE_TRDEPENDS : ("depends", "%s is required to run %s"), 398 TYPE_TRDEPENDS : ("depends", "%s is required to run %s"),
@@ -509,33 +507,47 @@ class LayerSource(models.Model):
509 507
510 TYPE_LOCAL = 0 508 TYPE_LOCAL = 0
511 TYPE_LAYERINDEX = 1 509 TYPE_LAYERINDEX = 1
510 TYPE_IMPORTED = 2
512 SOURCE_TYPE = ( 511 SOURCE_TYPE = (
513 (TYPE_LOCAL, "local"), 512 (TYPE_LOCAL, "local"),
514 (TYPE_LAYERINDEX, "layerindex"), 513 (TYPE_LAYERINDEX, "layerindex"),
514 (TYPE_IMPORTED, "imported"),
515 ) 515 )
516 516
517 name = models.CharField(max_length=63) 517 name = models.CharField(max_length=63, unique = True)
518 sourcetype = models.IntegerField(choices=SOURCE_TYPE) 518 sourcetype = models.IntegerField(choices=SOURCE_TYPE)
519 apiurl = models.CharField(max_length=255, null=True, default=None) 519 apiurl = models.CharField(max_length=255, null=True, default=None)
520 520
521 def update(self):
522 """
523 Updates the local database information from the upstream layer source
524 """
525 raise Exception("Abstract, update() must be implemented by all LayerSource-derived classes (object is %s)" % str(vars(self)))
526
521 def save(self, *args, **kwargs): 527 def save(self, *args, **kwargs):
522 if isinstance(self, LocalLayerSource): 528 if isinstance(self, LocalLayerSource):
523 self.sourcetype = LayerSource.TYPE_LOCAL 529 self.sourcetype = LayerSource.TYPE_LOCAL
524 elif isinstance(self, LayerIndexLayerSource): 530 elif isinstance(self, LayerIndexLayerSource):
525 self.sourcetype = LayerSource.TYPE_LAYERINDEX 531 self.sourcetype = LayerSource.TYPE_LAYERINDEX
532 elif isinstance(self, ImportedLayerSource):
533 self.sourcetype = LayerSource.TYPE_IMPORTED
526 elif self.sourcetype == None: 534 elif self.sourcetype == None:
527 raise Exception("Invalid LayerSource type") 535 raise Exception("Unknown LayerSource-derived class. If you added a new layer source type, fill out all code stubs.")
528 return super(LayerSource, self).save(*args, **kwargs) 536 return super(LayerSource, self).save(*args, **kwargs)
529 537
530 def get_object(self): 538 def get_object(self):
531 if self.sourcetype is not None: 539 if self.sourcetype == LayerSource.TYPE_LOCAL:
532 if self.sourcetype == LayerSource.TYPE_LOCAL: 540 self.__class__ = LocalLayerSource
533 self.__class__ = LocalLayerSource 541 elif self.sourcetype == LayerSource.TYPE_LAYERINDEX:
534 if self.sourcetype == LayerSource.TYPE_LAYERINDEX: 542 self.__class__ = LayerIndexLayerSource
535 self.__class__ = LayerIndexLayerSource 543 elif self.sourcetype == LayerSource.TYPE_IMPORTED:
544 self.__class__ = ImportedLayerSource
545 else:
546 raise Exception("Unknown LayerSource type. If you added a new layer source type, fill out all code stubs.")
536 return self 547 return self
537 548
538 return "LS " + self.sourcetype + " " + self.name 549 def __unicode__(self):
550 return "%s (%s)" % (self.name, self.sourcetype)
539 551
540 552
541class LocalLayerSource(LayerSource): 553class LocalLayerSource(LayerSource):
@@ -547,11 +559,26 @@ class LocalLayerSource(LayerSource):
547 self.sourcetype = LayerSource.TYPE_LOCAL 559 self.sourcetype = LayerSource.TYPE_LOCAL
548 560
549 def update(self): 561 def update(self):
550 ''' 562 """
563 Fetches layer, recipe and machine information from local repository
564 """
565 pass
566
567class ImportedLayerSource(LayerSource):
568 class Meta(LayerSource._meta.__class__):
569 proxy = True
570
571 def __init__(self, *args, **kwargs):
572 super(ImportedLayerSource, self).__init__(args, kwargs)
573 self.sourcetype = LayerSource.TYPE_IMPORTED
574
575 def update(self):
576 """
551 Fetches layer, recipe and machine information from local repository 577 Fetches layer, recipe and machine information from local repository
552 ''' 578 """
553 pass 579 pass
554 580
581
555class LayerIndexLayerSource(LayerSource): 582class LayerIndexLayerSource(LayerSource):
556 class Meta(LayerSource._meta.__class__): 583 class Meta(LayerSource._meta.__class__):
557 proxy = True 584 proxy = True
@@ -566,9 +593,9 @@ class LayerIndexLayerSource(LayerSource):
566 return self.apiurl + "../branch/" + branch.name + "/" + objectype + "/?q=" + str(upid) 593 return self.apiurl + "../branch/" + branch.name + "/" + objectype + "/?q=" + str(upid)
567 594
568 def update(self): 595 def update(self):
569 ''' 596 """
570 Fetches layer, recipe and machine information from remote repository 597 Fetches layer, recipe and machine information from remote repository
571 ''' 598 """
572 assert self.apiurl is not None 599 assert self.apiurl is not None
573 from django.db import IntegrityError 600 from django.db import IntegrityError
574 601
@@ -601,7 +628,7 @@ class LayerIndexLayerSource(LayerSource):
601 return 628 return
602 629
603 # update branches; only those that we already have names listed in the Releases table 630 # update branches; only those that we already have names listed in the Releases table
604 whitelist_branch_names = map(lambda x: x.branch.name, Release.objects.all()) 631 whitelist_branch_names = map(lambda x: x.branch_name, Release.objects.all())
605 632
606 branches_info = _get_json_response(apilinks['branches'] 633 branches_info = _get_json_response(apilinks['branches']
607 + "?filter=name:%s" % "OR".join(whitelist_branch_names)) 634 + "?filter=name:%s" % "OR".join(whitelist_branch_names))
@@ -713,16 +740,31 @@ class BitbakeVersion(models.Model):
713 740
714 741
715class Release(models.Model): 742class Release(models.Model):
743 """ A release is a project template, used to pre-populate Project settings with a configuration set """
716 name = models.CharField(max_length=32, unique = True) 744 name = models.CharField(max_length=32, unique = True)
717 description = models.CharField(max_length=255) 745 description = models.CharField(max_length=255)
718 bitbake_version = models.ForeignKey(BitbakeVersion) 746 bitbake_version = models.ForeignKey(BitbakeVersion)
719 branch = models.ForeignKey('Branch') 747 branch_name = models.CharField(max_length=50, default = "")
720 helptext = models.TextField(null=True) 748 helptext = models.TextField(null=True)
721 749
750 def __unicode__(self):
751 return "%s (%s)" % (self.name, self.branch_name)
752
753class ReleaseLayerSourcePriority(models.Model):
754 """ Each release selects layers from the set up layer sources, ordered by priority """
755 release = models.ForeignKey("Release")
756 layer_source = models.ForeignKey("LayerSource")
757 priority = models.IntegerField(default = 0)
758
759 def __unicode__(self):
760 return "%s-%s:%d" % (self.release.name, self.layer_source.name, self.priority)
761 class Meta:
762 unique_together = (('release', 'layer_source'),)
763
722 764
723class ReleaseDefaultLayer(models.Model): 765class ReleaseDefaultLayer(models.Model):
724 release = models.ForeignKey(Release) 766 release = models.ForeignKey(Release)
725 layer = models.ForeignKey('Layer') 767 layer_name = models.CharField(max_length=100, default="")
726 768
727 769
728# Branch class is synced with layerindex.Branch, branches can only come from remote layer indexes 770# Branch class is synced with layerindex.Branch, branches can only come from remote layer indexes
@@ -760,7 +802,7 @@ class Layer(models.Model):
760 description = models.TextField(null = True, default = None) 802 description = models.TextField(null = True, default = None)
761 803
762 def __unicode__(self): 804 def __unicode__(self):
763 return "L " + self.name 805 return "%s / %s " % (self.name, self.layer_source)
764 806
765 class Meta: 807 class Meta:
766 unique_together = (("layer_source", "up_id"), ("layer_source", "name")) 808 unique_together = (("layer_source", "up_id"), ("layer_source", "name"))
@@ -831,9 +873,21 @@ class Layer_Version(models.Model):
831 return None 873 return None
832 return self._handle_url_path(self.layer.vcs_web_tree_base_url, '') 874 return self._handle_url_path(self.layer.vcs_web_tree_base_url, '')
833 875
876 def get_equivalents_wpriority(self, project):
877 """ Returns an ordered layerversion list that satisfies a LayerVersionDependency using the layer name and the current Project Releases' LayerSource priority """
878 def _get_ls_priority(ls):
879 try:
880 return ls.releaselayersourcepriority_set.get(release=project.release).priority
881 except ReleaseLayerSourcePriority.DoesNotExist:
882 raise
883 return sorted(
884 Layer_Version.objects.filter( layer__name = self.layer.name, up_branch__name = self.up_branch.name ),
885 key = lambda x: _get_ls_priority(x.layer_source),
886 reverse = False)
887
834 888
835 def __unicode__(self): 889 def __unicode__(self):
836 return "LV " + str(self.layer) + " " + self.commit 890 return str(self.layer) + " (" + self.commit +")"
837 891
838 class Meta: 892 class Meta:
839 unique_together = ("layer_source", "up_id") 893 unique_together = ("layer_source", "up_id")
@@ -853,6 +907,9 @@ class ProjectLayer(models.Model):
853 layercommit = models.ForeignKey(Layer_Version, null=True) 907 layercommit = models.ForeignKey(Layer_Version, null=True)
854 optional = models.BooleanField(default = True) 908 optional = models.BooleanField(default = True)
855 909
910 def __unicode__(self):
911 return "%s, %s" % (self.project.name, self.layercommit)
912
856 class Meta: 913 class Meta:
857 unique_together = (("project", "layercommit"),) 914 unique_together = (("project", "layercommit"),)
858 915
diff --git a/bitbake/lib/toaster/orm/tests.py b/bitbake/lib/toaster/orm/tests.py
index f2f561b..b965d8e 100644
--- a/bitbake/lib/toaster/orm/tests.py
+++ b/bitbake/lib/toaster/orm/tests.py
@@ -1,16 +1,19 @@
1from django.test import TestCase 1from django.test import TestCase
2from orm.models import LocalLayerSource, LayerIndexLayerSource, LayerSource 2from orm.models import LocalLayerSource, LayerIndexLayerSource, ImportedLayerSource, LayerSource
3from orm.models import Branch 3from orm.models import Branch
4 4
5class LayerSourceVerifyInheritanceSaveLoad(TestCase): 5class LayerSourceVerifyInheritanceSaveLoad(TestCase):
6 def test_object_creation(self): 6 def test_object_creation(self):
7 lls = LayerSource.objects.create(name = "a1", sourcetype = LayerSource.TYPE_LOCAL, apiurl = "") 7 lls = LayerSource.objects.create(name = "a1", sourcetype = LayerSource.TYPE_LOCAL, apiurl = "")
8 lils = LayerSource.objects.create(name = "a1", sourcetype = LayerSource.TYPE_LAYERINDEX, apiurl = "") 8 lils = LayerSource.objects.create(name = "a2", sourcetype = LayerSource.TYPE_LAYERINDEX, apiurl = "")
9 imls = LayerSource.objects.create(name = "a3", sourcetype = LayerSource.TYPE_IMPORTED, apiurl = "")
9 10
10 print LayerSource.objects.all() 11 import pprint
12 pprint.pprint([(x.__class__,vars(x)) for x in LayerSource.objects.all()])
11 13
12 self.assertTrue(True in map(lambda x: isinstance(x, LocalLayerSource), LayerSource.objects.all())) 14 self.assertTrue(True in map(lambda x: isinstance(x, LocalLayerSource), LayerSource.objects.all()))
13 self.assertTrue(True in map(lambda x: isinstance(x, LayerIndexLayerSource), LayerSource.objects.all())) 15 self.assertTrue(True in map(lambda x: isinstance(x, LayerIndexLayerSource), LayerSource.objects.all()))
16 self.assertTrue(True in map(lambda x: isinstance(x, ImportedLayerSource), LayerSource.objects.all()))
14 17
15 def test_duplicate_error(self): 18 def test_duplicate_error(self):
16 def duplicate(): 19 def duplicate():
@@ -18,7 +21,7 @@ class LayerSourceVerifyInheritanceSaveLoad(TestCase):
18 LayerSource.objects.create(name = "a1", sourcetype = LayerSource.TYPE_LOCAL, apiurl = "") 21 LayerSource.objects.create(name = "a1", sourcetype = LayerSource.TYPE_LOCAL, apiurl = "")
19 22
20 self.assertRaises(Exception, duplicate) 23 self.assertRaises(Exception, duplicate)
21 24
22 25
23 26
24class LILSUpdateTestCase(TestCase): 27class LILSUpdateTestCase(TestCase):
diff --git a/bitbake/lib/toaster/toastergui/static/js/projectapp.js b/bitbake/lib/toaster/toastergui/static/js/projectapp.js
index 9f9a064..e9b07c7 100644
--- a/bitbake/lib/toaster/toastergui/static/js/projectapp.js
+++ b/bitbake/lib/toaster/toastergui/static/js/projectapp.js
@@ -173,6 +173,8 @@ projectApp.controller('prjCtrl', function($scope, $modal, $http, $interval, $loc
173 if (_data.error != "ok") { 173 if (_data.error != "ok") {
174 alert("Failed XHR request (" + _status + "): " + _data.error); 174 alert("Failed XHR request (" + _status + "): " + _data.error);
175 console.error("Failed XHR request: ", _data, _status, _headers, _config); 175 console.error("Failed XHR request: ", _data, _status, _headers, _config);
176 // stop refreshing hte page
177 $interval.cancel($scope.pollHandle);
176 deffered.reject(_data.error); 178 deffered.reject(_data.error);
177 } 179 }
178 else { 180 else {
diff --git a/bitbake/lib/toaster/toastergui/templates/layers.html b/bitbake/lib/toaster/toastergui/templates/layers.html
index 8cb079d..2bca84b 100644
--- a/bitbake/lib/toaster/toastergui/templates/layers.html
+++ b/bitbake/lib/toaster/toastergui/templates/layers.html
@@ -9,9 +9,9 @@
9{% block projectinfomain %} 9{% block projectinfomain %}
10 <div class="page-header"> 10 <div class="page-header">
11 <h1> 11 <h1>
12 {% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %} 12 {% if request.GET.filter and total_count > 0 or request.GET.search and total_count > 0 %}
13 {{objects.paginator.count}} layer{{objects.paginator.count|pluralize}} found 13 {{total_count}} layer{{total_count|pluralize}} found
14 {% elif request.GET.filter and objects.paginator.count == 0 or request.GET.search and objects.paginator.count == 0 %} 14 {% elif request.GET.filter and total_count == 0 or request.GET.search and total_count == 0 %}
15 No layers found 15 No layers found
16 {%else%} 16 {%else%}
17 All layers 17 All layers
diff --git a/bitbake/lib/toaster/toastergui/templates/project.html b/bitbake/lib/toaster/toastergui/templates/project.html
index 4e8a7e2..e1ef824 100644
--- a/bitbake/lib/toaster/toastergui/templates/project.html
+++ b/bitbake/lib/toaster/toastergui/templates/project.html
@@ -236,9 +236,9 @@ vim: expandtab tabstop=2
236 <p><a href="{% url 'layers' %}">View all layers</a> | <a href="{% url 'importlayer' %}">Import layer</a></p> 236 <p><a href="{% url 'layers' %}">View all layers</a> | <a href="{% url 'importlayer' %}">Import layer</a></p>
237 <ul class="unstyled configuration-list"> 237 <ul class="unstyled configuration-list">
238 <li ng-repeat="l in layers track by l.id" class="animate-repeat"> 238 <li ng-repeat="l in layers track by l.id" class="animate-repeat">
239 <a href="{[l.layerdetailurl]}" target="_#" class="layer-info" data-toggle="tooltip" tooltip="{[l.branch.layersource]} | {[l.branch.name]}">{[l.name]} </a> 239 <a href="{[l.layerdetailurl]}" target="_#" class="layer-info" data-toggle="tooltip" tooltip="{[l.giturl]} | {[l.branch.name]}">{[l.name]}</a>
240 <i class="icon-trash" ng-click="layerDel(l.id)" tooltip="Delete"></i> 240 <i class="icon-trash" ng-click="layerDel(l.id)" tooltip="Delete"></i>
241 </li> 241 </li>
242 </ul> 242 </ul>
243 </div> 243 </div>
244 244
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index 5e92c24..1b4bb9f 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -1881,7 +1881,10 @@ if toastermain.settings.MANAGED:
1881 "MANAGED" : toastermain.settings.MANAGED 1881 "MANAGED" : toastermain.settings.MANAGED
1882 } 1882 }
1883 if 'project_id' in request.session: 1883 if 'project_id' in request.session:
1884 ret['project'] = Project.objects.get(pk = request.session['project_id']) 1884 try:
1885 ret['project'] = Project.objects.get(pk = request.session['project_id'])
1886 except Project.DoesNotExist:
1887 del request.session['project_id']
1885 return ret 1888 return ret
1886 1889
1887 # new project 1890 # new project
@@ -1989,6 +1992,7 @@ if toastermain.settings.MANAGED:
1989 "id": x.layercommit.pk, 1992 "id": x.layercommit.pk,
1990 "orderid": x.pk, 1993 "orderid": x.pk,
1991 "name" : x.layercommit.layer.name, 1994 "name" : x.layercommit.layer.name,
1995 "giturl": x.layercommit.layer.vcs_url,
1992 "url": x.layercommit.layer.layer_index_url, 1996 "url": x.layercommit.layer.layer_index_url,
1993 "layerdetailurl": reverse("layerdetails", args=(x.layercommit.layer.pk,)), 1997 "layerdetailurl": reverse("layerdetails", args=(x.layercommit.layer.pk,)),
1994 "branch" : { "name" : x.layercommit.up_branch.name, "layersource" : x.layercommit.up_branch.layer_source.name}}, 1998 "branch" : { "name" : x.layercommit.up_branch.name, "layersource" : x.layercommit.up_branch.layer_source.name}},
@@ -2053,6 +2057,9 @@ if toastermain.settings.MANAGED:
2053 except Exception as e: 2057 except Exception as e:
2054 return HttpResponse(jsonfilter({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json") 2058 return HttpResponse(jsonfilter({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json")
2055 2059
2060
2061
2062
2056 def xhr_projectedit(request, pid): 2063 def xhr_projectedit(request, pid):
2057 try: 2064 try:
2058 prj = Project.objects.get(id = pid) 2065 prj = Project.objects.get(id = pid)
@@ -2078,11 +2085,14 @@ if toastermain.settings.MANAGED:
2078 # we need to change the layers 2085 # we need to change the layers
2079 for i in prj.projectlayer_set.all(): 2086 for i in prj.projectlayer_set.all():
2080 # find and add a similarly-named layer on the new branch 2087 # find and add a similarly-named layer on the new branch
2081 lv = Layer_Version.objects.filter(layer__name = i.layercommit.layer.name, up_branch__release = prj.release) 2088 try:
2082 if lv.count() == 1: 2089 lv = Layer_Version.objects.filter(layer__name = i.layercommit.layer.name, up_branch__name = prj.release.branch_name)[0].get_equivalents_wpriority(prj)[0]
2083 ProjectLayer.objects.get_or_create(project = prj, layercommit = lv[0]) 2090 ProjectLayer.objects.get_or_create(project = prj, layercommit = lv)
2084 # get rid of the old entry 2091 except IndexError:
2085 i.delete() 2092 pass
2093 finally:
2094 # get rid of the old entry
2095 i.delete()
2086 2096
2087 if 'machineName' in request.POST: 2097 if 'machineName' in request.POST:
2088 machinevar = prj.projectvariable_set.get(name="MACHINE") 2098 machinevar = prj.projectvariable_set.get(name="MACHINE")
@@ -2092,7 +2102,7 @@ if toastermain.settings.MANAGED:
2092 # return all project settings 2102 # return all project settings
2093 return HttpResponse(jsonfilter( { 2103 return HttpResponse(jsonfilter( {
2094 "error": "ok", 2104 "error": "ok",
2095 "layers" : map(lambda x: {"id": x.layercommit.pk, "orderid" : x.pk, "name" : x.layercommit.layer.name, "url": x.layercommit.layer.layer_index_url, "layerdetailurl": reverse("layerdetails", args=(x.layercommit.layer.pk,)), "branch" : { "name" : x.layercommit.up_branch.name, "layersource" : x.layercommit.up_branch.layer_source.name}}, prj.projectlayer_set.all().order_by("id")), 2105 "layers" : map(lambda x: {"id": x.layercommit.pk, "orderid" : x.pk, "name" : x.layercommit.layer.name, "giturl" : x.layercommit.layer.vcs_url, "url": x.layercommit.layer.layer_index_url, "layerdetailurl": reverse("layerdetails", args=(x.layercommit.layer.pk,)), "branch" : { "name" : x.layercommit.up_branch.name, "layersource" : x.layercommit.up_branch.layer_source.name}}, prj.projectlayer_set.all().order_by("id")),
2096 "builds" : _project_recent_build_list(prj), 2106 "builds" : _project_recent_build_list(prj),
2097 "variables": map(lambda x: (x.name, x.value), prj.projectvariable_set.all()), 2107 "variables": map(lambda x: (x.name, x.value), prj.projectvariable_set.all()),
2098 "machine": {"name": prj.projectvariable_set.get(name="MACHINE").value}, 2108 "machine": {"name": prj.projectvariable_set.get(name="MACHINE").value},
@@ -2107,45 +2117,46 @@ if toastermain.settings.MANAGED:
2107 @csrf_exempt 2117 @csrf_exempt
2108 def xhr_datatypeahead(request): 2118 def xhr_datatypeahead(request):
2109 try: 2119 try:
2120 prj = None
2121 if 'project_id' in request.session:
2122 prj = Project.objects.get(pk = request.session['project_id'])
2123
2110 # returns layers for current project release that are not in the project set 2124 # returns layers for current project release that are not in the project set
2111 if request.GET['type'] == "layers": 2125 if request.GET['type'] == "layers":
2112 queryset_all = Layer_Version.objects.all() 2126 queryset_all = Layer_Version.objects.filter(layer__name__icontains=request.GET.get('value',''))
2113 if 'project_id' in request.session: 2127 queryset_all = queryset_all.filter(up_branch__name= prj.release.branch_name).exclude(pk__in = [x.id for x in reduce(lambda x, y: list(x) + list(y), map(lambda x: x.layercommit.get_equivalents_wpriority(prj), prj.projectlayer_set.all()))])
2114 prj = Project.objects.get(pk = request.session['project_id']) 2128
2115 queryset_all = queryset_all.filter(up_branch__release = prj.release).exclude(pk__in = map(lambda x: x.layercommit_id, prj.projectlayer_set.all())) 2129 queryset_all = set([x.get_equivalents_wpriority(prj)[0] for x in queryset_all[:8]])
2116 queryset_all = queryset_all.filter(layer__name__icontains=request.GET.get('value','')) 2130
2117 return HttpResponse(jsonfilter( { "error":"ok", 2131 return HttpResponse(jsonfilter( { "error":"ok",
2118 "list" : map( lambda x: {"id": x.pk, "name": x.layer.name, "detail": "(" + x.layer.layer_source.name + (")" if x.up_branch == None else " | "+x.up_branch.name+")")}, 2132 "list" : map( lambda x: {"id": x.pk, "name": "%s" % (x.layer.name, ), "detail": "(" + x.layer.vcs_url + (")" if x.up_branch == None else " | "+x.up_branch.name+")")},
2119 queryset_all[:8]) 2133 queryset_all)
2120 }), content_type = "application/json") 2134 }), content_type = "application/json")
2121 2135
2136
2122 # returns layer dependencies for a layer, excluding current project layers 2137 # returns layer dependencies for a layer, excluding current project layers
2123 if request.GET['type'] == "layerdeps": 2138 if request.GET['type'] == "layerdeps":
2124 queryset_all = LayerVersionDependency.objects.filter(layer_version_id = request.GET['value']) 2139 queryset_all = LayerVersionDependency.objects.filter(layer_version_id = request.GET['value'])
2125 2140 queryset_all = queryset_all.exclude(depends_on__in = reduce(lambda x, y: list(x) + list(y), map(lambda x: x.layercommit.get_equivalents_wpriority(prj), prj.projectlayer_set.all())))
2126 if 'project_id' in request.session:
2127 prj = Project.objects.get(pk = request.session['project_id'])
2128 queryset_all = queryset_all.exclude(depends_on__in = map(lambda x: x.layercommit, prj.projectlayer_set.all()))
2129
2130 queryset_all.order_by("-up_id"); 2141 queryset_all.order_by("-up_id");
2131 2142
2132 return HttpResponse(jsonfilter( { "error":"ok", 2143 return HttpResponse(jsonfilter( { "error":"ok",
2133 "list" : map( 2144 "list" : map(
2134 lambda x: {"id": x.pk, "name": x.layer.name, "detail": "(" + x.layer.layer_source.name + (")" if x.up_branch == None else " | "+x.up_branch.name+")"), 2145 lambda x: {"id": x.pk, "name": x.layer.name, "detail": "(" + x.layer.layer_source.name + (")" if x.up_branch == None else " | "+x.up_branch.name+")"),
2135 "layerdetailurl" : reverse('layerdetails', args=(x.pk,))}, 2146 "giturl": x.layer.vcs_url, "layerdetailurl" : reverse('layerdetails', args=(x.pk,))},
2136 map(lambda x: x.depends_on, queryset_all)) 2147 map(lambda x: x.depends_on.get_equivalents_wpriority(prj)[0], queryset_all))
2137 }), content_type = "application/json") 2148 }), content_type = "application/json")
2138 2149
2150
2139 # returns layer versions that would be deleted on the new release__pk 2151 # returns layer versions that would be deleted on the new release__pk
2140 if request.GET['type'] == "versionlayers": 2152 if request.GET['type'] == "versionlayers":
2141 if not 'project_id' in request.session: 2153 if not 'project_id' in request.session:
2142 raise Exception("This call cannot makes no sense outside a project context") 2154 raise Exception("This call cannot makes no sense outside a project context")
2143 2155
2144 retval = [] 2156 retval = []
2145 prj = Project.objects.get(pk = request.session['project_id'])
2146 for i in prj.projectlayer_set.all(): 2157 for i in prj.projectlayer_set.all():
2147 lv = Layer_Version.objects.filter(layer__name = i.layercommit.layer.name, up_branch__release__pk=request.GET['value']) 2158 lv = Layer_Version.objects.filter(layer__name = i.layercommit.layer.name, up_branch__name = Release.objects.get(pk=request.GET['value']).branch_name)
2148 if lv.count() != 1: # there is no layer_version with the new release id, and the same name 2159 if lv.count() < 1: # there is no layer_version with the new release id, and the same name
2149 retval.append(i) 2160 retval.append(i)
2150 2161
2151 return HttpResponse(jsonfilter( {"error":"ok", 2162 return HttpResponse(jsonfilter( {"error":"ok",
@@ -2153,11 +2164,11 @@ if toastermain.settings.MANAGED:
2153 lambda x: {"id": x.layercommit.pk, "name": x.layercommit.layer.name, "detail": "(" + x.layercommit.layer.layer_source.name + (")" if x.layercommit.up_branch == None else " | "+x.layercommit.up_branch.name+")")}, 2164 lambda x: {"id": x.layercommit.pk, "name": x.layercommit.layer.name, "detail": "(" + x.layercommit.layer.layer_source.name + (")" if x.layercommit.up_branch == None else " | "+x.layercommit.up_branch.name+")")},
2154 retval) }), content_type = "application/json") 2165 retval) }), content_type = "application/json")
2155 2166
2167
2156 # returns targets provided by current project layers 2168 # returns targets provided by current project layers
2157 if request.GET['type'] == "targets": 2169 if request.GET['type'] == "targets":
2158 queryset_all = Recipe.objects.all() 2170 queryset_all = Recipe.objects.all()
2159 if 'project_id' in request.session: 2171 queryset_all = queryset_all.filter(layer_version__in = reduce(lambda x, y: list(x) + list(y), map(lambda x: x.layercommit.get_equivalents_wpriority(prj), ProjectLayer.objects.filter(project = prj))))
2160 queryset_all = queryset_all.filter(layer_version__layer__in = map(lambda x: x.layercommit.layer, ProjectLayer.objects.filter(project_id=request.session['project_id'])))
2161 return HttpResponse(jsonfilter({ "error":"ok", 2172 return HttpResponse(jsonfilter({ "error":"ok",
2162 "list" : map ( lambda x: {"id": x.pk, "name": x.name, "detail":"[" + x.layer_version.layer.name+ (" | " + x.layer_version.up_branch.name + "]" if x.layer_version.up_branch is not None else "]")}, 2173 "list" : map ( lambda x: {"id": x.pk, "name": x.name, "detail":"[" + x.layer_version.layer.name+ (" | " + x.layer_version.up_branch.name + "]" if x.layer_version.up_branch is not None else "]")},
2163 queryset_all.filter(name__icontains=request.GET.get('value',''))[:8]), 2174 queryset_all.filter(name__icontains=request.GET.get('value',''))[:8]),
@@ -2208,13 +2219,14 @@ if toastermain.settings.MANAGED:
2208 queryset_all = Layer_Version.objects.all() 2219 queryset_all = Layer_Version.objects.all()
2209 2220
2210 prj = Project.objects.get(pk = request.session['project_id']) 2221 prj = Project.objects.get(pk = request.session['project_id'])
2211 queryset_all = queryset_all.filter(up_branch__release = prj.release) 2222 queryset_all = queryset_all.filter(up_branch__name = prj.release.branch_name)
2212 2223
2213 queryset_with_search = _get_queryset(Layer_Version, queryset_all, None, search_term, ordering_string, '-layer__name') 2224 queryset_all = _get_queryset(Layer_Version, queryset_all, filter_string, search_term, ordering_string, '-layer__name')
2214 queryset = _get_queryset(Layer_Version, queryset_all, filter_string, search_term, ordering_string, '-layer__name') 2225
2226 objects_all= list(set([x.get_equivalents_wpriority(prj)[0] for x in queryset_all[:pagesize]]))
2215 2227
2216 # retrieve the objects that will be displayed in the table; layers a paginator and gets a page range to display 2228 # retrieve the objects that will be displayed in the table; layers a paginator and gets a page range to display
2217 layer_info = _build_page_range(Paginator(queryset, request.GET.get('count', 10)),request.GET.get('page', 1)) 2229 layer_info = _build_page_range(Paginator(objects_all, request.GET.get('count', 10)),request.GET.get('page', 1))
2218 2230
2219 2231
2220 context = { 2232 context = {
@@ -2222,7 +2234,7 @@ if toastermain.settings.MANAGED:
2222 'objects' : layer_info, 2234 'objects' : layer_info,
2223 'objectname' : "layers", 2235 'objectname' : "layers",
2224 'default_orderby' : 'layer__name:+', 2236 'default_orderby' : 'layer__name:+',
2225 'total_count': queryset_with_search.count(), 2237 'total_count': queryset_all.count(),
2226 2238
2227 'tablecols' : [ 2239 'tablecols' : [
2228 { 'name': 'Layer', 2240 { 'name': 'Layer',
@@ -2241,7 +2253,7 @@ if toastermain.settings.MANAGED:
2241 'filter': { 2253 'filter': {
2242 'class': 'layer', 2254 'class': 'layer',
2243 'label': 'Show:', 2255 'label': 'Show:',
2244 'options': map(lambda x: (x.name + " layers", 'layer_source__pk:' + str(x.id), queryset_with_search.filter(layer_source__pk = x.id).count() ), LayerSource.objects.all()), 2256 'options': map(lambda x: (x.name + " layers", 'layer_source__pk:' + str(x.id), queryset_all.filter(layer_source__pk = x.id).count() ), LayerSource.objects.all()),
2245 } 2257 }
2246 }, 2258 },
2247 { 'name': 'Git repository URL', 2259 { 'name': 'Git repository URL',
@@ -2269,8 +2281,8 @@ if toastermain.settings.MANAGED:
2269 'class': 'add-del-layers', 2281 'class': 'add-del-layers',
2270 'label': 'Show:', 2282 'label': 'Show:',
2271 'options': [ 2283 'options': [
2272 ('Layers added to this project', "projectlayer__project:" + str(prj.id), queryset_with_search.filter(projectlayer__project = prj.id).count()), 2284 ('Layers added to this project', "projectlayer__project:" + str(prj.id), queryset_all.filter(projectlayer__project = prj.id).count()),
2273 ('Layers not added to this project', "projectlayer__project:NOT" + str(prj.id), queryset_with_search.exclude(projectlayer__project = prj.id).count()), 2285 ('Layers not added to this project', "projectlayer__project:NOT" + str(prj.id), queryset_all.exclude(projectlayer__project = prj.id).count()),
2274 ] 2286 ]
2275 2287
2276 } 2288 }
@@ -2300,7 +2312,7 @@ if toastermain.settings.MANAGED:
2300 (filter_string, search_term, ordering_string) = _search_tuple(request, Recipe) 2312 (filter_string, search_term, ordering_string) = _search_tuple(request, Recipe)
2301 2313
2302 prj = Project.objects.get(pk = request.session['project_id']) 2314 prj = Project.objects.get(pk = request.session['project_id'])
2303 queryset_all = Recipe.objects.filter(Q(layer_version__up_branch__release = prj.release) | Q(layer_version__build__in = prj.build_set.all())) 2315 queryset_all = Recipe.objects.filter(Q(layer_version__up_branch__name= prj.release.name) | Q(layer_version__build__in = prj.build_set.all()))
2304 2316
2305 queryset_with_search = _get_queryset(Recipe, queryset_all, None, search_term, ordering_string, '-name') 2317 queryset_with_search = _get_queryset(Recipe, queryset_all, None, search_term, ordering_string, '-name')
2306 2318
@@ -2404,7 +2416,7 @@ if toastermain.settings.MANAGED:
2404 2416
2405 queryset_all = Machine.objects.all() 2417 queryset_all = Machine.objects.all()
2406# if 'project_id' in request.session: 2418# if 'project_id' in request.session:
2407# queryset_all = queryset_all.filter(Q(layer_version__up_branch__release = Project.objects.get(request.session['project_id']).release) | Q(layer_version__build__in = Project.objects.get(request.session['project_id']).build_set.all())) 2419# queryset_all = queryset_all.filter(Q(layer_version__up_branch__name = Project.objects.get(request.session['project_id']).release.branch_name) | Q(layer_version__build__in = Project.objects.get(request.session['project_id']).build_set.all()))
2408 2420
2409 queryset_with_search = _get_queryset(Machine, queryset_all, None, search_term, ordering_string, '-name') 2421 queryset_with_search = _get_queryset(Machine, queryset_all, None, search_term, ordering_string, '-name')
2410 queryset = _get_queryset(Machine, queryset_all, filter_string, search_term, ordering_string, '-name') 2422 queryset = _get_queryset(Machine, queryset_all, filter_string, search_term, ordering_string, '-name')