diff options
| -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) |
