diff options
| author | Michael Wood <michael.g.wood@intel.com> | 2016-12-09 16:52:45 +0000 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-12-12 20:44:53 +0000 |
| commit | 7e80e501fb05021d4f4b6793462c488445cb4d89 (patch) | |
| tree | df966256a8a94e780e74b82fa9ae369e7c46a551 | |
| parent | 90d995c63717f869ef68976f7d0778e87af989f2 (diff) | |
| download | poky-7e80e501fb05021d4f4b6793462c488445cb4d89.tar.gz | |
bitbake: toaster: api Add layer Add api
Add layer adding REST api and remove old views method.
(Bitbake rev: 0c8e41d2217fd568a84e857d1be230fcfd4bb5c7)
Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
| -rw-r--r-- | bitbake/lib/toaster/toastergui/api.py | 101 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/templates/importlayer.html | 2 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/urls.py | 6 | ||||
| -rwxr-xr-x | bitbake/lib/toaster/toastergui/views.py | 115 |
4 files changed, 103 insertions, 121 deletions
diff --git a/bitbake/lib/toaster/toastergui/api.py b/bitbake/lib/toaster/toastergui/api.py index 4851047bfa..5be633ed11 100644 --- a/bitbake/lib/toaster/toastergui/api.py +++ b/bitbake/lib/toaster/toastergui/api.py | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | import re | 21 | import re |
| 22 | import logging | 22 | import logging |
| 23 | import json | ||
| 23 | from collections import Counter | 24 | from collections import Counter |
| 24 | 25 | ||
| 25 | from orm.models import Project, ProjectTarget, Build, Layer_Version | 26 | from orm.models import Project, ProjectTarget, Build, Layer_Version |
| @@ -136,14 +137,17 @@ class XhrBuildRequest(View): | |||
| 136 | 137 | ||
| 137 | 138 | ||
| 138 | class XhrLayer(View): | 139 | class XhrLayer(View): |
| 139 | """ Get and Update Layer information """ | 140 | """ Delete, Get, Add and Update Layer information |
| 141 | |||
| 142 | Methods: POST DELETE PUT | ||
| 143 | """ | ||
| 140 | 144 | ||
| 141 | def post(self, request, *args, **kwargs): | 145 | def post(self, request, *args, **kwargs): |
| 142 | """ | 146 | """ |
| 143 | Update a layer | 147 | Update a layer |
| 144 | 148 | ||
| 145 | Entry point: /xhr_layer/<layerversion_id> | ||
| 146 | Method: POST | 149 | Method: POST |
| 150 | Entry point: /xhr_layer/<layerversion_id> | ||
| 147 | 151 | ||
| 148 | Args: | 152 | Args: |
| 149 | vcs_url, dirpath, commit, up_branch, summary, description, | 153 | vcs_url, dirpath, commit, up_branch, summary, description, |
| @@ -201,9 +205,100 @@ class XhrLayer(View): | |||
| 201 | return error_response("Could not update layer version entry: %s" | 205 | return error_response("Could not update layer version entry: %s" |
| 202 | % e) | 206 | % e) |
| 203 | 207 | ||
| 204 | return JsonResponse({"error": "ok"}) | 208 | return error_response("ok") |
| 209 | |||
| 210 | def put(self, request, *args, **kwargs): | ||
| 211 | """ Add a new layer | ||
| 212 | |||
| 213 | Method: PUT | ||
| 214 | Entry point: /xhr_layer/ | ||
| 215 | Args: | ||
| 216 | project_id, name, | ||
| 217 | [vcs_url, dir_path, git_ref], [local_source_dir], [layer_deps | ||
| 218 | (csv)] | ||
| 219 | |||
| 220 | """ | ||
| 221 | try: | ||
| 222 | project = Project.objects.get(pk=kwargs['pid']) | ||
| 223 | |||
| 224 | layer_data = json.loads(request.body.decode('utf-8')) | ||
| 225 | |||
| 226 | # We require a unique layer name as otherwise the lists of layers | ||
| 227 | # becomes very confusing | ||
| 228 | existing_layers = \ | ||
| 229 | project.get_all_compatible_layer_versions().values_list( | ||
| 230 | "layer__name", | ||
| 231 | flat=True) | ||
| 232 | |||
| 233 | add_to_project = False | ||
| 234 | layer_deps_added = [] | ||
| 235 | if 'add_to_project' in layer_data: | ||
| 236 | add_to_project = True | ||
| 237 | |||
| 238 | if layer_data['name'] in existing_layers: | ||
| 239 | return JsonResponse({"error": "layer-name-exists"}) | ||
| 240 | |||
| 241 | layer = Layer.objects.create(name=layer_data['name']) | ||
| 242 | |||
| 243 | layer_version = Layer_Version.objects.create( | ||
| 244 | layer=layer, | ||
| 245 | project=project, | ||
| 246 | layer_source=LayerSource.TYPE_IMPORTED) | ||
| 247 | |||
| 248 | # Local layer | ||
| 249 | if 'local_source_dir' in layer_data: | ||
| 250 | layer.local_source_dir = layer_data['local_source_dir'] | ||
| 251 | # git layer | ||
| 252 | elif 'vcs_url' in layer_data: | ||
| 253 | layer.vcs_url = layer_data['vcs_url'] | ||
| 254 | layer_version.dirpath = layer_data['dir_path'] | ||
| 255 | layer_version.commit = layer_data['get_ref'] | ||
| 256 | layer_version.branch = layer_data['get_ref'] | ||
| 257 | |||
| 258 | layer.save() | ||
| 259 | layer_version.save() | ||
| 260 | |||
| 261 | if add_to_project: | ||
| 262 | ProjectLayer.objects.get_or_create( | ||
| 263 | layercommit=layer_version, project=project) | ||
| 264 | |||
| 265 | # Add the layer dependencies | ||
| 266 | if 'layer_deps' in layer_data: | ||
| 267 | for layer_dep_id in layer_data['layer_deps'].split(","): | ||
| 268 | layer_dep = Layer_Version.objects.get(pk=layer_dep_id) | ||
| 269 | LayerVersionDependency.objects.get_or_create( | ||
| 270 | layer_version=layer_version, depends_on=layer_dep) | ||
| 271 | |||
| 272 | # Add layer deps to the project if specified | ||
| 273 | if add_to_project: | ||
| 274 | created, pl = ProjectLayer.objects.get_or_create( | ||
| 275 | layercommit=layer_dep, project=project) | ||
| 276 | layer_deps_added.append( | ||
| 277 | {'name': layer_dep.layer.name, | ||
| 278 | 'layerdetailurl': | ||
| 279 | layer_dep.get_detailspage_url(project.pk)}) | ||
| 280 | |||
| 281 | except Layer_Version.DoesNotExist: | ||
| 282 | return error_response("layer-dep-not-found") | ||
| 283 | except Project.DoesNotExist: | ||
| 284 | return error_response("project-not-found") | ||
| 285 | except KeyError: | ||
| 286 | return error_response("incorrect-parameters") | ||
| 287 | |||
| 288 | return JsonResponse({'error': "ok", | ||
| 289 | 'imported_layer': { | ||
| 290 | 'name': layer.name, | ||
| 291 | 'layerdetailurl': | ||
| 292 | layer_version.get_detailspage_url()}, | ||
| 293 | 'deps_added': layer_deps_added}) | ||
| 205 | 294 | ||
| 206 | def delete(self, request, *args, **kwargs): | 295 | def delete(self, request, *args, **kwargs): |
| 296 | """ Delete an imported layer | ||
| 297 | |||
| 298 | Method: DELETE | ||
| 299 | Entry point: /xhr_layer/<layerversion_id> | ||
| 300 | |||
| 301 | """ | ||
| 207 | try: | 302 | try: |
| 208 | # We currently only allow Imported layers to be deleted | 303 | # We currently only allow Imported layers to be deleted |
| 209 | layer_version = Layer_Version.objects.get( | 304 | layer_version = Layer_Version.objects.get( |
diff --git a/bitbake/lib/toaster/toastergui/templates/importlayer.html b/bitbake/lib/toaster/toastergui/templates/importlayer.html index 1f426969af..bd507b5677 100644 --- a/bitbake/lib/toaster/toastergui/templates/importlayer.html +++ b/bitbake/lib/toaster/toastergui/templates/importlayer.html | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | <script> | 13 | <script> |
| 14 | $(document).ready(function (){ | 14 | $(document).ready(function (){ |
| 15 | var ctx = { | 15 | var ctx = { |
| 16 | xhrImportLayerUrl : "{% url 'xhr_importlayer' %}", | 16 | xhrLayerUrl : "{% url 'xhr_layer' project.id %}", |
| 17 | }; | 17 | }; |
| 18 | 18 | ||
| 19 | try { | 19 | try { |
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py index ece9ac1696..29f0d96ba7 100644 --- a/bitbake/lib/toaster/toastergui/urls.py +++ b/bitbake/lib/toaster/toastergui/urls.py | |||
| @@ -190,12 +190,14 @@ urlpatterns = patterns('toastergui.views', | |||
| 190 | url(r'^xhr_configvaredit/(?P<pid>\d+)$', 'xhr_configvaredit', | 190 | url(r'^xhr_configvaredit/(?P<pid>\d+)$', 'xhr_configvaredit', |
| 191 | name='xhr_configvaredit'), | 191 | name='xhr_configvaredit'), |
| 192 | 192 | ||
| 193 | url(r'^xhr_importlayer/$', 'xhr_importlayer', name='xhr_importlayer'), | ||
| 194 | |||
| 195 | url(r'^xhr_layer/(?P<pid>\d+)/(?P<layerversion_id>\d+)$', | 193 | url(r'^xhr_layer/(?P<pid>\d+)/(?P<layerversion_id>\d+)$', |
| 196 | api.XhrLayer.as_view(), | 194 | api.XhrLayer.as_view(), |
| 197 | name='xhr_layer'), | 195 | name='xhr_layer'), |
| 198 | 196 | ||
| 197 | url(r'^xhr_layer/(?P<pid>\d+)$', | ||
| 198 | api.XhrLayer.as_view(), | ||
| 199 | name='xhr_layer'), | ||
| 200 | |||
| 199 | # JS Unit tests | 201 | # JS Unit tests |
| 200 | url(r'^js-unit-tests/$', 'jsunittests', name='js-unit-tests'), | 202 | url(r'^js-unit-tests/$', 'jsunittests', name='js-unit-tests'), |
| 201 | 203 | ||
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 2efb0fd56c..94b630a8f7 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
| @@ -1509,121 +1509,6 @@ if True: | |||
| 1509 | return HttpResponse(json.dumps({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json") | 1509 | return HttpResponse(json.dumps({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json") |
| 1510 | 1510 | ||
| 1511 | 1511 | ||
| 1512 | def xhr_importlayer(request): | ||
| 1513 | if ('vcs_url' not in request.POST or | ||
| 1514 | 'name' not in request.POST or | ||
| 1515 | 'git_ref' not in request.POST or | ||
| 1516 | 'project_id' not in request.POST): | ||
| 1517 | return HttpResponse(jsonfilter({"error": "Missing parameters; requires vcs_url, name, git_ref and project_id"}), content_type = "application/json") | ||
| 1518 | |||
| 1519 | layers_added = []; | ||
| 1520 | |||
| 1521 | # Rudimentary check for any possible html tags | ||
| 1522 | for val in request.POST.values(): | ||
| 1523 | if "<" in val: | ||
| 1524 | return HttpResponse(jsonfilter( | ||
| 1525 | {"error": "Invalid character <"}), | ||
| 1526 | content_type="application/json") | ||
| 1527 | |||
| 1528 | prj = Project.objects.get(pk=request.POST['project_id']) | ||
| 1529 | |||
| 1530 | # Strip trailing/leading whitespace from all values | ||
| 1531 | # put into a new dict because POST one is immutable. | ||
| 1532 | post_data = dict() | ||
| 1533 | for key,val in request.POST.items(): | ||
| 1534 | post_data[key] = val.strip() | ||
| 1535 | |||
| 1536 | |||
| 1537 | try: | ||
| 1538 | layer, layer_created = Layer.objects.get_or_create(name=post_data['name']) | ||
| 1539 | except MultipleObjectsReturned: | ||
| 1540 | return HttpResponse(jsonfilter({"error": "hint-layer-exists"}), content_type = "application/json") | ||
| 1541 | |||
| 1542 | if layer: | ||
| 1543 | if layer_created: | ||
| 1544 | layer.vcs_url = post_data.get('vcs_url') | ||
| 1545 | layer.local_source_dir = post_data.get('local_source_dir') | ||
| 1546 | layer.up_date = timezone.now() | ||
| 1547 | layer.save() | ||
| 1548 | else: | ||
| 1549 | # We have an existing layer by this name, let's see if the git | ||
| 1550 | # url is the same, if it is then we can just create a new layer | ||
| 1551 | # version for this layer. Otherwise we need to bail out. | ||
| 1552 | if layer.vcs_url != post_data['vcs_url']: | ||
| 1553 | return HttpResponse(jsonfilter({"error": "hint-layer-exists-with-different-url" , "current_url" : layer.vcs_url, "current_id": layer.id }), content_type = "application/json") | ||
| 1554 | |||
| 1555 | layer_version, version_created = \ | ||
| 1556 | Layer_Version.objects.get_or_create( | ||
| 1557 | layer_source=LayerSource.TYPE_IMPORTED, | ||
| 1558 | layer=layer, project=prj, | ||
| 1559 | release=prj.release, | ||
| 1560 | branch=post_data['git_ref'], | ||
| 1561 | commit=post_data['git_ref'], | ||
| 1562 | dirpath=post_data['dir_path']) | ||
| 1563 | |||
| 1564 | if layer_version: | ||
| 1565 | if not version_created: | ||
| 1566 | return HttpResponse(jsonfilter({"error": | ||
| 1567 | "hint-layer-version-exists", | ||
| 1568 | "existing_layer_version": | ||
| 1569 | layer_version.id }), | ||
| 1570 | content_type = "application/json") | ||
| 1571 | |||
| 1572 | layer_version.layer_source = LayerSource.TYPE_IMPORTED | ||
| 1573 | |||
| 1574 | layer_version.up_date = timezone.now() | ||
| 1575 | layer_version.save() | ||
| 1576 | |||
| 1577 | # Add the dependencies specified for this new layer | ||
| 1578 | if ('layer_deps' in post_data and | ||
| 1579 | version_created and | ||
| 1580 | len(post_data["layer_deps"]) > 0): | ||
| 1581 | for layer_dep_id in post_data["layer_deps"].split(","): | ||
| 1582 | |||
| 1583 | layer_dep_obj = Layer_Version.objects.get(pk=layer_dep_id) | ||
| 1584 | LayerVersionDependency.objects.get_or_create(layer_version=layer_version, depends_on=layer_dep_obj) | ||
| 1585 | # Now add them to the project, we could get an execption | ||
| 1586 | # if the project now contains the exact | ||
| 1587 | # dependency already (like modified on another page) | ||
| 1588 | try: | ||
| 1589 | prj_layer, prj_layer_created = ProjectLayer.objects.get_or_create(layercommit=layer_dep_obj, project=prj) | ||
| 1590 | except IntegrityError as e: | ||
| 1591 | logger.warning("Integrity error while saving Project Layers: %s (original %s)" % (e, e.__cause__)) | ||
| 1592 | continue | ||
| 1593 | |||
| 1594 | if prj_layer_created: | ||
| 1595 | layerdepdetailurl = reverse('layerdetails', args=(prj.id, layer_dep_obj.pk)) | ||
| 1596 | layers_added.append({'id': layer_dep_obj.id, 'name': Layer.objects.get(id=layer_dep_obj.layer_id).name, 'layerdetailurl': layerdepdetailurl }) | ||
| 1597 | |||
| 1598 | |||
| 1599 | # If an old layer version exists in our project then remove it | ||
| 1600 | for prj_layers in ProjectLayer.objects.filter(project=prj): | ||
| 1601 | dup_layer_v = Layer_Version.objects.filter(id=prj_layers.layercommit_id, layer_id=layer.id) | ||
| 1602 | if len(dup_layer_v) >0 : | ||
| 1603 | prj_layers.delete() | ||
| 1604 | |||
| 1605 | # finally add the imported layer (version id) to the project | ||
| 1606 | ProjectLayer.objects.create(layercommit=layer_version, project=prj,optional=1) | ||
| 1607 | |||
| 1608 | else: | ||
| 1609 | # We didn't create a layer version so back out now and clean up. | ||
| 1610 | if layer_created: | ||
| 1611 | layer.delete() | ||
| 1612 | |||
| 1613 | return HttpResponse(jsonfilter({"error": "Uncaught error: Could not create layer version"}), content_type = "application/json") | ||
| 1614 | |||
| 1615 | layerdetailurl = reverse('layerdetails', args=(prj.id, layer_version.pk)) | ||
| 1616 | |||
| 1617 | json_response = {"error": "ok", | ||
| 1618 | "imported_layer" : { | ||
| 1619 | "name" : layer.name, | ||
| 1620 | "id": layer_version.id, | ||
| 1621 | "layerdetailurl": layerdetailurl, | ||
| 1622 | }, | ||
| 1623 | "deps_added": layers_added } | ||
| 1624 | |||
| 1625 | return HttpResponse(jsonfilter(json_response), content_type = "application/json") | ||
| 1626 | |||
| 1627 | def customrecipe_download(request, pid, recipe_id): | 1512 | def customrecipe_download(request, pid, recipe_id): |
| 1628 | recipe = get_object_or_404(CustomImageRecipe, pk=recipe_id) | 1513 | recipe = get_object_or_404(CustomImageRecipe, pk=recipe_id) |
| 1629 | 1514 | ||
