diff options
Diffstat (limited to 'bitbake/lib/toaster/orm/models.py')
-rw-r--r-- | bitbake/lib/toaster/orm/models.py | 481 |
1 files changed, 103 insertions, 378 deletions
diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py index 048399f34d..1daec9c25a 100644 --- a/bitbake/lib/toaster/orm/models.py +++ b/bitbake/lib/toaster/orm/models.py | |||
@@ -22,7 +22,7 @@ | |||
22 | from __future__ import unicode_literals | 22 | from __future__ import unicode_literals |
23 | 23 | ||
24 | from django.db import models, IntegrityError | 24 | from django.db import models, IntegrityError |
25 | from django.db.models import F, Q, Avg, Max, Sum, Count | 25 | from django.db.models import F, Q, Sum, Count |
26 | from django.utils import timezone | 26 | from django.utils import timezone |
27 | from django.utils.encoding import force_bytes | 27 | from django.utils.encoding import force_bytes |
28 | 28 | ||
@@ -117,39 +117,48 @@ class ToasterSetting(models.Model): | |||
117 | def __unicode__(self): | 117 | def __unicode__(self): |
118 | return "Setting %s = %s" % (self.name, self.value) | 118 | return "Setting %s = %s" % (self.name, self.value) |
119 | 119 | ||
120 | |||
120 | class ProjectManager(models.Manager): | 121 | class ProjectManager(models.Manager): |
121 | def create_project(self, name, release): | 122 | def create_project(self, name, release): |
122 | if release is not None: | 123 | if release is not None: |
123 | prj = self.model(name = name, bitbake_version = release.bitbake_version, release = release) | 124 | prj = self.model(name=name, |
125 | bitbake_version=release.bitbake_version, | ||
126 | release=release) | ||
124 | else: | 127 | else: |
125 | prj = self.model(name = name, bitbake_version = None, release = None) | 128 | prj = self.model(name=name, |
129 | bitbake_version=None, | ||
130 | release=None) | ||
126 | 131 | ||
127 | prj.save() | 132 | prj.save() |
128 | 133 | ||
129 | for defaultconf in ToasterSetting.objects.filter(name__startswith="DEFCONF_"): | 134 | for defaultconf in ToasterSetting.objects.filter( |
135 | name__startswith="DEFCONF_"): | ||
130 | name = defaultconf.name[8:] | 136 | name = defaultconf.name[8:] |
131 | ProjectVariable.objects.create( project = prj, | 137 | ProjectVariable.objects.create(project=prj, |
132 | name = name, | 138 | name=name, |
133 | value = defaultconf.value) | 139 | value=defaultconf.value) |
134 | 140 | ||
135 | if release is None: | 141 | if release is None: |
136 | return prj | 142 | return prj |
137 | 143 | ||
138 | for rdl in release.releasedefaultlayer_set.all(): | 144 | for rdl in release.releasedefaultlayer_set.all(): |
139 | try: | 145 | lv = Layer_Version.objects.filter( |
140 | lv = Layer_Version.objects.filter(layer__name = rdl.layer_name, up_branch__name = release.branch_name)[0].get_equivalents_wpriority(prj)[0] | 146 | layer__name=rdl.layer_name, |
141 | ProjectLayer.objects.create( project = prj, | 147 | up_branch__name=release.branch_name).first() |
142 | layercommit = lv, | 148 | |
143 | optional = False ) | 149 | if lv: |
144 | except IndexError: | 150 | ProjectLayer.objects.create(project=prj, |
145 | # we may have no valid layer version objects, and that's ok | 151 | layercommit=lv, |
146 | pass | 152 | optional=False) |
153 | else: | ||
154 | logger.warning("Default project layer %s not found" % | ||
155 | rdl.layer_name) | ||
147 | 156 | ||
148 | return prj | 157 | return prj |
149 | 158 | ||
150 | # return single object with is_default = True | 159 | # return single object with is_default = True |
151 | def get_or_create_default_project(self): | 160 | def get_or_create_default_project(self): |
152 | projects = super(ProjectManager, self).filter(is_default = True) | 161 | projects = super(ProjectManager, self).filter(is_default=True) |
153 | 162 | ||
154 | if len(projects) > 1: | 163 | if len(projects) > 1: |
155 | raise Exception('Inconsistent project data: multiple ' + | 164 | raise Exception('Inconsistent project data: multiple ' + |
@@ -157,7 +166,8 @@ class ProjectManager(models.Manager): | |||
157 | elif len(projects) < 1: | 166 | elif len(projects) < 1: |
158 | options = { | 167 | options = { |
159 | 'name': 'Command line builds', | 168 | 'name': 'Command line builds', |
160 | 'short_description': 'Project for builds started outside Toaster', | 169 | 'short_description': |
170 | 'Project for builds started outside Toaster', | ||
161 | 'is_default': True | 171 | 'is_default': True |
162 | } | 172 | } |
163 | project = Project.objects.create(**options) | 173 | project = Project.objects.create(**options) |
@@ -1126,21 +1136,27 @@ class Target_Installed_Package(models.Model): | |||
1126 | target = models.ForeignKey(Target) | 1136 | target = models.ForeignKey(Target) |
1127 | package = models.ForeignKey(Package, related_name='buildtargetlist_package') | 1137 | package = models.ForeignKey(Package, related_name='buildtargetlist_package') |
1128 | 1138 | ||
1139 | |||
1129 | class Package_File(models.Model): | 1140 | class Package_File(models.Model): |
1130 | package = models.ForeignKey(Package, related_name='buildfilelist_package') | 1141 | package = models.ForeignKey(Package, related_name='buildfilelist_package') |
1131 | path = models.FilePathField(max_length=255, blank=True) | 1142 | path = models.FilePathField(max_length=255, blank=True) |
1132 | size = models.IntegerField() | 1143 | size = models.IntegerField() |
1133 | 1144 | ||
1145 | |||
1134 | class Recipe(models.Model): | 1146 | class Recipe(models.Model): |
1135 | search_allowed_fields = ['name', 'version', 'file_path', 'section', 'summary', 'description', 'license', 'layer_version__layer__name', 'layer_version__branch', 'layer_version__commit', 'layer_version__local_path', 'layer_version__layer_source__name'] | 1147 | search_allowed_fields = ['name', 'version', 'file_path', 'section', |
1148 | 'summary', 'description', 'license', | ||
1149 | 'layer_version__layer__name', | ||
1150 | 'layer_version__branch', 'layer_version__commit', | ||
1151 | 'layer_version__local_path', | ||
1152 | 'layer_version__layer_source'] | ||
1136 | 1153 | ||
1137 | layer_source = models.ForeignKey('LayerSource', default = None, null = True) # from where did we get this recipe | 1154 | up_date = models.DateTimeField(null=True, default=None) |
1138 | up_id = models.IntegerField(null = True, default = None) # id of entry in the source | ||
1139 | up_date = models.DateTimeField(null = True, default = None) | ||
1140 | 1155 | ||
1141 | name = models.CharField(max_length=100, blank=True) # pn | 1156 | name = models.CharField(max_length=100, blank=True) |
1142 | version = models.CharField(max_length=100, blank=True) # pv | 1157 | version = models.CharField(max_length=100, blank=True) |
1143 | layer_version = models.ForeignKey('Layer_Version', related_name='recipe_layer_version') | 1158 | layer_version = models.ForeignKey('Layer_Version', |
1159 | related_name='recipe_layer_version') | ||
1144 | summary = models.TextField(blank=True) | 1160 | summary = models.TextField(blank=True) |
1145 | description = models.TextField(blank=True) | 1161 | description = models.TextField(blank=True) |
1146 | section = models.CharField(max_length=100, blank=True) | 1162 | section = models.CharField(max_length=100, blank=True) |
@@ -1151,13 +1167,6 @@ class Recipe(models.Model): | |||
1151 | pathflags = models.CharField(max_length=200, blank=True) | 1167 | pathflags = models.CharField(max_length=200, blank=True) |
1152 | is_image = models.BooleanField(default=False) | 1168 | is_image = models.BooleanField(default=False) |
1153 | 1169 | ||
1154 | def get_layersource_view_url(self): | ||
1155 | if self.layer_source is None: | ||
1156 | return "" | ||
1157 | |||
1158 | url = self.layer_source.get_object_view(self.layer_version.up_branch, "recipes", self.name) | ||
1159 | return url | ||
1160 | |||
1161 | def __unicode__(self): | 1170 | def __unicode__(self): |
1162 | return "Recipe " + self.name + ":" + self.version | 1171 | return "Recipe " + self.name + ":" + self.version |
1163 | 1172 | ||
@@ -1203,8 +1212,6 @@ class Recipe_Dependency(models.Model): | |||
1203 | 1212 | ||
1204 | class Machine(models.Model): | 1213 | class Machine(models.Model): |
1205 | search_allowed_fields = ["name", "description", "layer_version__layer__name"] | 1214 | search_allowed_fields = ["name", "description", "layer_version__layer__name"] |
1206 | layer_source = models.ForeignKey('LayerSource', default = None, null = True) # from where did we get this machine | ||
1207 | up_id = models.IntegerField(null = True, default = None) # id of entry in the source | ||
1208 | up_date = models.DateTimeField(null = True, default = None) | 1215 | up_date = models.DateTimeField(null = True, default = None) |
1209 | 1216 | ||
1210 | layer_version = models.ForeignKey('Layer_Version') | 1217 | layer_version = models.ForeignKey('Layer_Version') |
@@ -1219,293 +1226,9 @@ class Machine(models.Model): | |||
1219 | def __unicode__(self): | 1226 | def __unicode__(self): |
1220 | return "Machine " + self.name + "(" + self.description + ")" | 1227 | return "Machine " + self.name + "(" + self.description + ")" |
1221 | 1228 | ||
1222 | class Meta: | ||
1223 | unique_together = ("layer_source", "up_id") | ||
1224 | |||
1225 | |||
1226 | from django.db.models.base import ModelBase | ||
1227 | 1229 | ||
1228 | class InheritanceMetaclass(ModelBase): | ||
1229 | def __call__(cls, *args, **kwargs): | ||
1230 | obj = super(InheritanceMetaclass, cls).__call__(*args, **kwargs) | ||
1231 | return obj.get_object() | ||
1232 | 1230 | ||
1233 | 1231 | ||
1234 | class LayerSource(models.Model): | ||
1235 | __metaclass__ = InheritanceMetaclass | ||
1236 | |||
1237 | class Meta: | ||
1238 | unique_together = (('sourcetype', 'apiurl'), ) | ||
1239 | |||
1240 | TYPE_LOCAL = 0 | ||
1241 | TYPE_LAYERINDEX = 1 | ||
1242 | TYPE_IMPORTED = 2 | ||
1243 | SOURCE_TYPE = ( | ||
1244 | (TYPE_LOCAL, "local"), | ||
1245 | (TYPE_LAYERINDEX, "layerindex"), | ||
1246 | (TYPE_IMPORTED, "imported"), | ||
1247 | ) | ||
1248 | |||
1249 | name = models.CharField(max_length=63, unique = True) | ||
1250 | sourcetype = models.IntegerField(choices=SOURCE_TYPE) | ||
1251 | apiurl = models.CharField(max_length=255, null=True, default=None) | ||
1252 | |||
1253 | def __init__(self, *args, **kwargs): | ||
1254 | super(LayerSource, self).__init__(*args, **kwargs) | ||
1255 | if self.sourcetype == LayerSource.TYPE_LOCAL: | ||
1256 | self.__class__ = LocalLayerSource | ||
1257 | elif self.sourcetype == LayerSource.TYPE_LAYERINDEX: | ||
1258 | self.__class__ = LayerIndexLayerSource | ||
1259 | elif self.sourcetype == LayerSource.TYPE_IMPORTED: | ||
1260 | self.__class__ = ImportedLayerSource | ||
1261 | elif self.sourcetype == None: | ||
1262 | raise Exception("Unknown LayerSource-derived class. If you added a new layer source type, fill out all code stubs.") | ||
1263 | |||
1264 | |||
1265 | def update(self): | ||
1266 | """ | ||
1267 | Updates the local database information from the upstream layer source | ||
1268 | """ | ||
1269 | raise Exception("Abstract, update() must be implemented by all LayerSource-derived classes (object is %s)" % str(vars(self))) | ||
1270 | |||
1271 | def save(self, *args, **kwargs): | ||
1272 | return super(LayerSource, self).save(*args, **kwargs) | ||
1273 | |||
1274 | def get_object(self): | ||
1275 | # preset an un-initilized object | ||
1276 | if None == self.name: | ||
1277 | self.name="" | ||
1278 | if None == self.apiurl: | ||
1279 | self.apiurl="" | ||
1280 | if None == self.sourcetype: | ||
1281 | self.sourcetype=LayerSource.TYPE_LOCAL | ||
1282 | |||
1283 | if self.sourcetype == LayerSource.TYPE_LOCAL: | ||
1284 | self.__class__ = LocalLayerSource | ||
1285 | elif self.sourcetype == LayerSource.TYPE_LAYERINDEX: | ||
1286 | self.__class__ = LayerIndexLayerSource | ||
1287 | elif self.sourcetype == LayerSource.TYPE_IMPORTED: | ||
1288 | self.__class__ = ImportedLayerSource | ||
1289 | else: | ||
1290 | raise Exception("Unknown LayerSource type. If you added a new layer source type, fill out all code stubs.") | ||
1291 | return self | ||
1292 | |||
1293 | def __unicode__(self): | ||
1294 | return "%s (%s)" % (self.name, self.sourcetype) | ||
1295 | |||
1296 | |||
1297 | class LocalLayerSource(LayerSource): | ||
1298 | class Meta(LayerSource._meta.__class__): | ||
1299 | proxy = True | ||
1300 | |||
1301 | def __init__(self, *args, **kwargs): | ||
1302 | super(LocalLayerSource, self).__init__(args, kwargs) | ||
1303 | self.sourcetype = LayerSource.TYPE_LOCAL | ||
1304 | |||
1305 | def update(self): | ||
1306 | """ | ||
1307 | Fetches layer, recipe and machine information from local repository | ||
1308 | """ | ||
1309 | pass | ||
1310 | |||
1311 | class ImportedLayerSource(LayerSource): | ||
1312 | class Meta(LayerSource._meta.__class__): | ||
1313 | proxy = True | ||
1314 | |||
1315 | def __init__(self, *args, **kwargs): | ||
1316 | super(ImportedLayerSource, self).__init__(args, kwargs) | ||
1317 | self.sourcetype = LayerSource.TYPE_IMPORTED | ||
1318 | |||
1319 | def update(self): | ||
1320 | """ | ||
1321 | Fetches layer, recipe and machine information from local repository | ||
1322 | """ | ||
1323 | pass | ||
1324 | |||
1325 | |||
1326 | class LayerIndexLayerSource(LayerSource): | ||
1327 | class Meta(LayerSource._meta.__class__): | ||
1328 | proxy = True | ||
1329 | |||
1330 | def __init__(self, *args, **kwargs): | ||
1331 | super(LayerIndexLayerSource, self).__init__(args, kwargs) | ||
1332 | self.sourcetype = LayerSource.TYPE_LAYERINDEX | ||
1333 | |||
1334 | def get_object_view(self, branch, objectype, upid): | ||
1335 | return self.apiurl + "../branch/" + branch.name + "/" + objectype + "/?q=" + str(upid) | ||
1336 | |||
1337 | def update(self): | ||
1338 | """ | ||
1339 | Fetches layer, recipe and machine information from remote repository | ||
1340 | """ | ||
1341 | assert self.apiurl is not None | ||
1342 | from django.db import transaction, connection | ||
1343 | |||
1344 | import json | ||
1345 | import os | ||
1346 | |||
1347 | try: | ||
1348 | from urllib.request import urlopen, URLError | ||
1349 | from urllib.parse import urlparse | ||
1350 | except ImportError: | ||
1351 | from urllib2 import urlopen, URLError | ||
1352 | from urlparse import urlparse | ||
1353 | |||
1354 | proxy_settings = os.environ.get("http_proxy", None) | ||
1355 | oe_core_layer = 'openembedded-core' | ||
1356 | |||
1357 | def _get_json_response(apiurl = self.apiurl): | ||
1358 | _parsedurl = urlparse(apiurl) | ||
1359 | path = _parsedurl.path | ||
1360 | |||
1361 | try: | ||
1362 | res = urlopen(apiurl) | ||
1363 | except URLError as e: | ||
1364 | raise Exception("Failed to read %s: %s" % (path, e.reason)) | ||
1365 | |||
1366 | return json.loads(res.read().decode('utf-8')) | ||
1367 | |||
1368 | # verify we can get the basic api | ||
1369 | try: | ||
1370 | apilinks = _get_json_response() | ||
1371 | except Exception as e: | ||
1372 | import traceback | ||
1373 | if proxy_settings is not None: | ||
1374 | logger.info("EE: Using proxy %s" % proxy_settings) | ||
1375 | logger.warning("EE: could not connect to %s, skipping update: %s\n%s" % (self.apiurl, e, traceback.format_exc())) | ||
1376 | return | ||
1377 | |||
1378 | # update branches; only those that we already have names listed in the | ||
1379 | # Releases table | ||
1380 | whitelist_branch_names = [rel.branch_name for rel in Release.objects.all()] | ||
1381 | if len(whitelist_branch_names) == 0: | ||
1382 | raise Exception("Failed to make list of branches to fetch") | ||
1383 | |||
1384 | logger.debug("Fetching branches") | ||
1385 | branches_info = _get_json_response(apilinks['branches'] | ||
1386 | + "?filter=name:%s" % "OR".join(whitelist_branch_names)) | ||
1387 | for bi in branches_info: | ||
1388 | b, created = Branch.objects.get_or_create(layer_source = self, name = bi['name']) | ||
1389 | b.up_id = bi['id'] | ||
1390 | b.up_date = bi['updated'] | ||
1391 | b.name = bi['name'] | ||
1392 | b.short_description = bi['short_description'] | ||
1393 | b.save() | ||
1394 | |||
1395 | # update layers | ||
1396 | layers_info = _get_json_response(apilinks['layerItems']) | ||
1397 | |||
1398 | for li in layers_info: | ||
1399 | # Special case for the openembedded-core layer | ||
1400 | if li['name'] == oe_core_layer: | ||
1401 | try: | ||
1402 | # If we have an existing openembedded-core for example | ||
1403 | # from the toasterconf.json augment the info using the | ||
1404 | # layerindex rather than duplicate it | ||
1405 | oe_core_l = Layer.objects.get(name=oe_core_layer) | ||
1406 | # Take ownership of the layer as now coming from the | ||
1407 | # layerindex | ||
1408 | oe_core_l.layer_source = self | ||
1409 | oe_core_l.up_id = li['id'] | ||
1410 | oe_core_l.summary = li['summary'] | ||
1411 | oe_core_l.description = li['description'] | ||
1412 | oe_core_l.save() | ||
1413 | continue | ||
1414 | |||
1415 | except Layer.DoesNotExist: | ||
1416 | pass | ||
1417 | |||
1418 | l, created = Layer.objects.get_or_create(layer_source = self, name = li['name']) | ||
1419 | l.up_id = li['id'] | ||
1420 | l.up_date = li['updated'] | ||
1421 | l.vcs_url = li['vcs_url'] | ||
1422 | l.vcs_web_url = li['vcs_web_url'] | ||
1423 | l.vcs_web_tree_base_url = li['vcs_web_tree_base_url'] | ||
1424 | l.vcs_web_file_base_url = li['vcs_web_file_base_url'] | ||
1425 | l.summary = li['summary'] | ||
1426 | l.description = li['description'] | ||
1427 | l.save() | ||
1428 | |||
1429 | # update layerbranches/layer_versions | ||
1430 | logger.debug("Fetching layer information") | ||
1431 | layerbranches_info = _get_json_response(apilinks['layerBranches'] | ||
1432 | + "?filter=branch:%s" % "OR".join(map(lambda x: str(x.up_id), [i for i in Branch.objects.filter(layer_source = self) if i.up_id is not None] )) | ||
1433 | ) | ||
1434 | |||
1435 | for lbi in layerbranches_info: | ||
1436 | lv, created = Layer_Version.objects.get_or_create(layer_source = self, | ||
1437 | up_id = lbi['id'], | ||
1438 | layer=Layer.objects.get(layer_source = self, up_id = lbi['layer']) | ||
1439 | ) | ||
1440 | |||
1441 | lv.up_date = lbi['updated'] | ||
1442 | lv.up_branch = Branch.objects.get(layer_source = self, up_id = lbi['branch']) | ||
1443 | lv.branch = lbi['actual_branch'] | ||
1444 | lv.commit = lbi['actual_branch'] | ||
1445 | lv.dirpath = lbi['vcs_subdir'] | ||
1446 | lv.save() | ||
1447 | |||
1448 | # update layer dependencies | ||
1449 | layerdependencies_info = _get_json_response(apilinks['layerDependencies']) | ||
1450 | dependlist = {} | ||
1451 | for ldi in layerdependencies_info: | ||
1452 | try: | ||
1453 | lv = Layer_Version.objects.get(layer_source = self, up_id = ldi['layerbranch']) | ||
1454 | except Layer_Version.DoesNotExist as e: | ||
1455 | continue | ||
1456 | |||
1457 | if lv not in dependlist: | ||
1458 | dependlist[lv] = [] | ||
1459 | try: | ||
1460 | dependlist[lv].append(Layer_Version.objects.get(layer_source = self, layer__up_id = ldi['dependency'], up_branch = lv.up_branch)) | ||
1461 | except Layer_Version.DoesNotExist: | ||
1462 | logger.warning("Cannot find layer version (ls:%s), up_id:%s lv:%s" % (self, ldi['dependency'], lv)) | ||
1463 | |||
1464 | for lv in dependlist: | ||
1465 | LayerVersionDependency.objects.filter(layer_version = lv).delete() | ||
1466 | for lvd in dependlist[lv]: | ||
1467 | LayerVersionDependency.objects.get_or_create(layer_version = lv, depends_on = lvd) | ||
1468 | |||
1469 | |||
1470 | # update machines | ||
1471 | logger.debug("Fetching machine information") | ||
1472 | machines_info = _get_json_response(apilinks['machines'] | ||
1473 | + "?filter=layerbranch:%s" % "OR".join(map(lambda x: str(x.up_id), Layer_Version.objects.filter(layer_source = self))) | ||
1474 | ) | ||
1475 | |||
1476 | for mi in machines_info: | ||
1477 | mo, created = Machine.objects.get_or_create(layer_source = self, up_id = mi['id'], layer_version = Layer_Version.objects.get(layer_source = self, up_id = mi['layerbranch'])) | ||
1478 | mo.up_date = mi['updated'] | ||
1479 | mo.name = mi['name'] | ||
1480 | mo.description = mi['description'] | ||
1481 | mo.save() | ||
1482 | |||
1483 | # update recipes; paginate by layer version / layer branch | ||
1484 | logger.debug("Fetching target information") | ||
1485 | recipes_info = _get_json_response(apilinks['recipes'] | ||
1486 | + "?filter=layerbranch:%s" % "OR".join(map(lambda x: str(x.up_id), Layer_Version.objects.filter(layer_source = self))) | ||
1487 | ) | ||
1488 | for ri in recipes_info: | ||
1489 | try: | ||
1490 | ro, created = Recipe.objects.get_or_create(layer_source = self, up_id = ri['id'], layer_version = Layer_Version.objects.get(layer_source = self, up_id = ri['layerbranch'])) | ||
1491 | ro.up_date = ri['updated'] | ||
1492 | ro.name = ri['pn'] | ||
1493 | ro.version = ri['pv'] | ||
1494 | ro.summary = ri['summary'] | ||
1495 | ro.description = ri['description'] | ||
1496 | ro.section = ri['section'] | ||
1497 | ro.license = ri['license'] | ||
1498 | ro.homepage = ri['homepage'] | ||
1499 | ro.bugtracker = ri['bugtracker'] | ||
1500 | ro.file_path = ri['filepath'] + "/" + ri['filename'] | ||
1501 | if 'inherits' in ri: | ||
1502 | ro.is_image = 'image' in ri['inherits'].split() | ||
1503 | else: # workaround for old style layer index | ||
1504 | ro.is_image = "-image-" in ri['pn'] | ||
1505 | ro.save() | ||
1506 | except IntegrityError as e: | ||
1507 | logger.debug("Failed saving recipe, ignoring: %s (%s:%s)" % (e, ro.layer_version, ri['filepath']+"/"+ri['filename'])) | ||
1508 | ro.delete() | ||
1509 | 1232 | ||
1510 | class BitbakeVersion(models.Model): | 1233 | class BitbakeVersion(models.Model): |
1511 | 1234 | ||
@@ -1529,87 +1252,98 @@ class Release(models.Model): | |||
1529 | def __unicode__(self): | 1252 | def __unicode__(self): |
1530 | return "%s (%s)" % (self.name, self.branch_name) | 1253 | return "%s (%s)" % (self.name, self.branch_name) |
1531 | 1254 | ||
1532 | class ReleaseLayerSourcePriority(models.Model): | ||
1533 | """ Each release selects layers from the set up layer sources, ordered by priority """ | ||
1534 | release = models.ForeignKey("Release") | ||
1535 | layer_source = models.ForeignKey("LayerSource") | ||
1536 | priority = models.IntegerField(default = 0) | ||
1537 | |||
1538 | def __unicode__(self): | ||
1539 | return "%s-%s:%d" % (self.release.name, self.layer_source.name, self.priority) | ||
1540 | class Meta: | ||
1541 | unique_together = (('release', 'layer_source'),) | ||
1542 | |||
1543 | |||
1544 | class ReleaseDefaultLayer(models.Model): | 1255 | class ReleaseDefaultLayer(models.Model): |
1545 | release = models.ForeignKey(Release) | 1256 | release = models.ForeignKey(Release) |
1546 | layer_name = models.CharField(max_length=100, default="") | 1257 | layer_name = models.CharField(max_length=100, default="") |
1547 | 1258 | ||
1548 | 1259 | ||
1549 | # Branch class is synced with layerindex.Branch, branches can only come from remote layer indexes | 1260 | # Branch class is synced with layerindex.Branch, branches can only come |
1261 | # from remote layer indexes | ||
1550 | class Branch(models.Model): | 1262 | class Branch(models.Model): |
1551 | layer_source = models.ForeignKey('LayerSource', null = True, default = True) | 1263 | # id of branch in the layerindex |
1552 | up_id = models.IntegerField(null = True, default = None) # id of branch in the source | 1264 | up_date = models.DateTimeField(null=True, default=None) |
1553 | up_date = models.DateTimeField(null = True, default = None) | ||
1554 | 1265 | ||
1555 | name = models.CharField(max_length=50) | 1266 | name = models.CharField(max_length=50) |
1556 | short_description = models.CharField(max_length=50, blank=True) | 1267 | short_description = models.CharField(max_length=50, blank=True) |
1557 | 1268 | ||
1558 | class Meta: | 1269 | class Meta: |
1559 | verbose_name_plural = "Branches" | 1270 | verbose_name_plural = "Branches" |
1560 | unique_together = (('layer_source', 'name'),('layer_source', 'up_id')) | ||
1561 | 1271 | ||
1562 | def __unicode__(self): | 1272 | def __unicode__(self): |
1563 | return self.name | 1273 | return self.name |
1564 | 1274 | ||
1565 | 1275 | ||
1566 | # Layer class synced with layerindex.LayerItem | 1276 | class LayerSource(object): |
1277 | """ Where the layer metadata came from """ | ||
1278 | TYPE_LOCAL = 0 | ||
1279 | TYPE_LAYERINDEX = 1 | ||
1280 | TYPE_IMPORTED = 2 | ||
1281 | TYPE_BUILD = 3 | ||
1282 | |||
1283 | SOURCE_TYPE = ( | ||
1284 | (TYPE_LOCAL, "local"), | ||
1285 | (TYPE_LAYERINDEX, "layerindex"), | ||
1286 | (TYPE_IMPORTED, "imported"), | ||
1287 | (TYPE_BUILD, "build"), | ||
1288 | ) | ||
1289 | |||
1290 | |||
1567 | class Layer(models.Model): | 1291 | class Layer(models.Model): |
1568 | layer_source = models.ForeignKey(LayerSource, null = True, default = None) # from where did we got this layer | 1292 | |
1569 | up_id = models.IntegerField(null = True, default = None) # id of layer in the remote source | 1293 | up_date = models.DateTimeField(null=True, default=timezone.now) |
1570 | up_date = models.DateTimeField(null = True, default = None) | ||
1571 | 1294 | ||
1572 | name = models.CharField(max_length=100) | 1295 | name = models.CharField(max_length=100) |
1573 | layer_index_url = models.URLField() | 1296 | layer_index_url = models.URLField() |
1574 | vcs_url = GitURLField(default = None, null = True) | 1297 | vcs_url = GitURLField(default=None, null=True) |
1575 | vcs_web_url = models.URLField(null = True, default = None) | 1298 | vcs_web_url = models.URLField(null=True, default=None) |
1576 | vcs_web_tree_base_url = models.URLField(null = True, default = None) | 1299 | vcs_web_tree_base_url = models.URLField(null=True, default=None) |
1577 | vcs_web_file_base_url = models.URLField(null = True, default = None) | 1300 | vcs_web_file_base_url = models.URLField(null=True, default=None) |
1578 | 1301 | ||
1579 | summary = models.TextField(help_text='One-line description of the layer', null = True, default = None) | 1302 | summary = models.TextField(help_text='One-line description of the layer', |
1580 | description = models.TextField(null = True, default = None) | 1303 | null=True, default=None) |
1304 | description = models.TextField(null=True, default=None) | ||
1581 | 1305 | ||
1582 | def __unicode__(self): | 1306 | def __unicode__(self): |
1583 | return "%s / %s " % (self.name, self.layer_source) | 1307 | return "%s / %s " % (self.name, self.summary) |
1584 | |||
1585 | class Meta: | ||
1586 | unique_together = (("layer_source", "up_id"), ("layer_source", "name")) | ||
1587 | 1308 | ||
1588 | 1309 | ||
1589 | # LayerCommit class is synced with layerindex.LayerBranch | ||
1590 | class Layer_Version(models.Model): | 1310 | class Layer_Version(models.Model): |
1591 | """ | 1311 | """ |
1592 | A Layer_Version either belongs to a single project or no project | 1312 | A Layer_Version either belongs to a single project or no project |
1593 | """ | 1313 | """ |
1594 | search_allowed_fields = ["layer__name", "layer__summary", "layer__description", "layer__vcs_url", "dirpath", "up_branch__name", "commit", "branch"] | 1314 | search_allowed_fields = ["layer__name", "layer__summary", |
1595 | build = models.ForeignKey(Build, related_name='layer_version_build', default = None, null = True) | 1315 | "layer__description", "layer__vcs_url", |
1316 | "dirpath", "up_branch__name", "commit", "branch"] | ||
1317 | |||
1318 | build = models.ForeignKey(Build, related_name='layer_version_build', | ||
1319 | default=None, null=True) | ||
1320 | |||
1596 | layer = models.ForeignKey(Layer, related_name='layer_version_layer') | 1321 | layer = models.ForeignKey(Layer, related_name='layer_version_layer') |
1597 | 1322 | ||
1598 | layer_source = models.ForeignKey(LayerSource, null = True, default = None) # from where did we get this Layer Version | 1323 | layer_source = models.IntegerField(choices=LayerSource.SOURCE_TYPE, |
1599 | up_id = models.IntegerField(null = True, default = None) # id of layerbranch in the remote source | 1324 | default=0) |
1600 | up_date = models.DateTimeField(null = True, default = None) | 1325 | |
1601 | up_branch = models.ForeignKey(Branch, null = True, default = None) | 1326 | up_date = models.DateTimeField(null=True, default=timezone.now) |
1602 | 1327 | ||
1603 | branch = models.CharField(max_length=80) # LayerBranch.actual_branch | 1328 | # layerindex specific field |
1604 | commit = models.CharField(max_length=100) # LayerBranch.vcs_last_rev | 1329 | up_branch = models.ForeignKey(Branch, null=True, default=None) |
1605 | dirpath = models.CharField(max_length=255, null = True, default = None) # LayerBranch.vcs_subdir | ||
1606 | priority = models.IntegerField(default = 0) # if -1, this is a default layer | ||
1607 | 1330 | ||
1608 | local_path = models.FilePathField(max_length=1024, default = "/") # where this layer was checked-out | 1331 | branch = models.CharField(max_length=80) |
1332 | commit = models.CharField(max_length=100) | ||
1333 | # If the layer is in a subdir | ||
1334 | dirpath = models.CharField(max_length=255, null=True, default=None) | ||
1609 | 1335 | ||
1610 | project = models.ForeignKey('Project', null = True, default = None) # Set if this layer is project-specific; always set for imported layers, and project-set branches | 1336 | # if -1, this is a default layer |
1337 | priority = models.IntegerField(default=0) | ||
1611 | 1338 | ||
1612 | # code lifted, with adaptations, from the layerindex-web application https://git.yoctoproject.org/cgit/cgit.cgi/layerindex-web/ | 1339 | # where this layer exists on the filesystem |
1340 | local_path = models.FilePathField(max_length=1024, default="/") | ||
1341 | |||
1342 | # Set if this layer is restricted to a particular project | ||
1343 | project = models.ForeignKey('Project', null=True, default=None) | ||
1344 | |||
1345 | # code lifted, with adaptations, from the layerindex-web application | ||
1346 | # https://git.yoctoproject.org/cgit/cgit.cgi/layerindex-web/ | ||
1613 | def _handle_url_path(self, base_url, path): | 1347 | def _handle_url_path(self, base_url, path): |
1614 | import re, posixpath | 1348 | import re, posixpath |
1615 | if base_url: | 1349 | if base_url: |
@@ -1651,18 +1385,14 @@ class Layer_Version(models.Model): | |||
1651 | def get_vcs_file_link_url(self, file_path=""): | 1385 | def get_vcs_file_link_url(self, file_path=""): |
1652 | if self.layer.vcs_web_file_base_url is None: | 1386 | if self.layer.vcs_web_file_base_url is None: |
1653 | return None | 1387 | return None |
1654 | return self._handle_url_path(self.layer.vcs_web_file_base_url, file_path) | 1388 | return self._handle_url_path(self.layer.vcs_web_file_base_url, |
1389 | file_path) | ||
1655 | 1390 | ||
1656 | def get_vcs_dirpath_link_url(self): | 1391 | def get_vcs_dirpath_link_url(self): |
1657 | if self.layer.vcs_web_tree_base_url is None: | 1392 | if self.layer.vcs_web_tree_base_url is None: |
1658 | return None | 1393 | return None |
1659 | return self._handle_url_path(self.layer.vcs_web_tree_base_url, '') | 1394 | return self._handle_url_path(self.layer.vcs_web_tree_base_url, '') |
1660 | 1395 | ||
1661 | def get_equivalents_wpriority(self, project): | ||
1662 | layer_versions = project.get_all_compatible_layer_versions() | ||
1663 | filtered = layer_versions.filter(layer__name = self.layer.name) | ||
1664 | return filtered.order_by("-layer_source__releaselayersourcepriority__priority") | ||
1665 | |||
1666 | def get_vcs_reference(self): | 1396 | def get_vcs_reference(self): |
1667 | if self.branch is not None and len(self.branch) > 0: | 1397 | if self.branch is not None and len(self.branch) > 0: |
1668 | return self.branch | 1398 | return self.branch |
@@ -1695,20 +1425,15 @@ class Layer_Version(models.Model): | |||
1695 | return sorted(result, key=lambda x: x.layer.name) | 1425 | return sorted(result, key=lambda x: x.layer.name) |
1696 | 1426 | ||
1697 | def __unicode__(self): | 1427 | def __unicode__(self): |
1698 | return "%d %s (VCS %s, Project %s)" % (self.pk, str(self.layer), self.get_vcs_reference(), self.build.project if self.build is not None else "No project") | 1428 | return ("id %d belongs to layer: %s" % (self.pk, self.layer.name)) |
1699 | 1429 | ||
1700 | class Meta: | ||
1701 | unique_together = ("layer_source", "up_id") | ||
1702 | 1430 | ||
1703 | class LayerVersionDependency(models.Model): | 1431 | class LayerVersionDependency(models.Model): |
1704 | layer_source = models.ForeignKey(LayerSource, null = True, default = None) # from where did we got this layer | ||
1705 | up_id = models.IntegerField(null = True, default = None) # id of layerbranch in the remote source | ||
1706 | |||
1707 | layer_version = models.ForeignKey(Layer_Version, related_name="dependencies") | ||
1708 | depends_on = models.ForeignKey(Layer_Version, related_name="dependees") | ||
1709 | 1432 | ||
1710 | class Meta: | 1433 | layer_version = models.ForeignKey(Layer_Version, |
1711 | unique_together = ("layer_source", "up_id") | 1434 | related_name="dependencies") |
1435 | depends_on = models.ForeignKey(Layer_Version, | ||
1436 | related_name="dependees") | ||
1712 | 1437 | ||
1713 | class ProjectLayer(models.Model): | 1438 | class ProjectLayer(models.Model): |
1714 | project = models.ForeignKey(Project) | 1439 | project = models.ForeignKey(Project) |