blob: 66114ff89e65f37467a8e1a2a0290d64e7b1ae77 [file] [log] [blame]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001#
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# BitBake Toaster Implementation
6#
Brad Bishopd7bf8c12018-02-25 22:55:05 -05007# Copyright (C) 2016-2017 Intel Corporation
Patrick Williamsc0f7c042017-02-23 20:41:17 -06008#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 2 as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
Brad Bishopd7bf8c12018-02-25 22:55:05 -050022from django.core.management.base import BaseCommand
Patrick Williamsc0f7c042017-02-23 20:41:17 -060023
24from orm.models import LayerSource, Layer, Release, Layer_Version
25from orm.models import LayerVersionDependency, Machine, Recipe
Brad Bishopd7bf8c12018-02-25 22:55:05 -050026from orm.models import Distro
27from orm.models import ToasterSetting
Patrick Williamsc0f7c042017-02-23 20:41:17 -060028
Patrick Williamsc124f4f2015-09-15 14:41:29 -050029import os
Patrick Williamsc0f7c042017-02-23 20:41:17 -060030import sys
31
Patrick Williamsc0f7c042017-02-23 20:41:17 -060032import logging
33import threading
34import time
35logger = logging.getLogger("toaster")
36
37DEFAULT_LAYERINDEX_SERVER = "http://layers.openembedded.org/layerindex/api/"
38
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080039# Add path to bitbake modules for layerindexlib
40# lib/toaster/orm/management/commands/lsupdates.py (abspath)
41# lib/toaster/orm/management/commands (dirname)
42# lib/toaster/orm/management (dirname)
43# lib/toaster/orm (dirname)
44# lib/toaster/ (dirname)
45# lib/ (dirname)
46path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
47sys.path.insert(0, path)
48
49import layerindexlib
50
Patrick Williamsc0f7c042017-02-23 20:41:17 -060051
52class Spinner(threading.Thread):
53 """ A simple progress spinner to indicate download/parsing is happening"""
54 def __init__(self, *args, **kwargs):
55 super(Spinner, self).__init__(*args, **kwargs)
56 self.setDaemon(True)
57 self.signal = True
58
59 def run(self):
60 os.system('setterm -cursor off')
61 while self.signal:
62 for char in ["/", "-", "\\", "|"]:
63 sys.stdout.write("\r" + char)
64 sys.stdout.flush()
65 time.sleep(0.25)
66 os.system('setterm -cursor on')
67
68 def stop(self):
69 self.signal = False
70
Patrick Williamsc124f4f2015-09-15 14:41:29 -050071
Brad Bishopd7bf8c12018-02-25 22:55:05 -050072class Command(BaseCommand):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060073 args = ""
74 help = "Updates locally cached information from a layerindex server"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050075
Patrick Williamsc0f7c042017-02-23 20:41:17 -060076 def mini_progress(self, what, i, total):
77 i = i + 1
78 pec = (float(i)/float(total))*100
79
80 sys.stdout.write("\rUpdating %s %d%%" %
81 (what,
82 pec))
83 sys.stdout.flush()
84 if int(pec) is 100:
85 sys.stdout.write("\n")
86 sys.stdout.flush()
87
88 def update(self):
89 """
90 Fetches layer, recipe and machine information from a layerindex
91 server
92 """
93 os.system('setterm -cursor off')
94
95 self.apiurl = DEFAULT_LAYERINDEX_SERVER
Brad Bishopd7bf8c12018-02-25 22:55:05 -050096 if ToasterSetting.objects.filter(name='CUSTOM_LAYERINDEX_SERVER').count() == 1:
97 self.apiurl = ToasterSetting.objects.get(name = 'CUSTOM_LAYERINDEX_SERVER').value
Patrick Williamsc0f7c042017-02-23 20:41:17 -060098
99 assert self.apiurl is not None
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600100
101 # update branches; only those that we already have names listed in the
102 # Releases table
103 whitelist_branch_names = [rel.branch_name
104 for rel in Release.objects.all()]
105 if len(whitelist_branch_names) == 0:
106 raise Exception("Failed to make list of branches to fetch")
107
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800108 logger.info("Fetching metadata for %s",
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600109 " ".join(whitelist_branch_names))
110
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800111 # We require a non-empty bb.data, but we can fake it with a dictionary
112 layerindex = layerindexlib.LayerIndex({"DUMMY" : "VALUE"})
113
114 http_progress = Spinner()
115 http_progress.start()
116
117 if whitelist_branch_names:
118 url_branches = ";branch=%s" % ','.join(whitelist_branch_names)
119 else:
120 url_branches = ""
121 layerindex.load_layerindex("%s%s" % (self.apiurl, url_branches))
122
123 http_progress.stop()
124
125 # We know we're only processing one entry, so we reference it here
126 # (this is cheating...)
127 index = layerindex.indexes[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600128
129 # Map the layer index branches to toaster releases
130 li_branch_id_to_toaster_release = {}
131
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800132 logger.info("Processing releases")
133
134 total = len(index.branches)
135 for i, id in enumerate(index.branches):
136 li_branch_id_to_toaster_release[id] = \
137 Release.objects.get(name=index.branches[id].name)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600138 self.mini_progress("Releases", i, total)
139
140 # keep a track of the layerindex (li) id mappings so that
141 # layer_versions can be created for these layers later on
142 li_layer_id_to_toaster_layer_id = {}
143
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800144 logger.info("Processing layers")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600145
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800146 total = len(index.layerItems)
147 for i, id in enumerate(index.layerItems):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600148 try:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800149 l, created = Layer.objects.get_or_create(name=index.layerItems[id].name)
150 l.up_date = index.layerItems[id].updated
151 l.summary = index.layerItems[id].summary
152 l.description = index.layerItems[id].description
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500153
154 if created:
155 # predefined layers in the fixtures (for example poky.xml)
156 # always preempt the Layer Index for these values
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800157 l.vcs_url = index.layerItems[id].vcs_url
158 l.vcs_web_url = index.layerItems[id].vcs_web_url
159 l.vcs_web_tree_base_url = index.layerItems[id].vcs_web_tree_base_url
160 l.vcs_web_file_base_url = index.layerItems[id].vcs_web_file_base_url
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600161 l.save()
162 except Layer.MultipleObjectsReturned:
163 logger.info("Skipped %s as we found multiple layers and "
164 "don't know which to update" %
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800165 index.layerItems[id].name)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600166
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800167 li_layer_id_to_toaster_layer_id[id] = l.pk
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600168
169 self.mini_progress("layers", i, total)
170
171 # update layer_versions
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800172 logger.info("Processing layer versions")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600173
174 # Map Layer index layer_branch object id to
175 # layer_version toaster object id
176 li_layer_branch_id_to_toaster_lv_id = {}
177
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800178 total = len(index.layerBranches)
179 for i, id in enumerate(index.layerBranches):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500180 # release as defined by toaster map to layerindex branch
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800181 release = li_branch_id_to_toaster_release[index.layerBranches[id].branch_id]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600182
183 try:
184 lv, created = Layer_Version.objects.get_or_create(
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600185 layer=Layer.objects.get(
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800186 pk=li_layer_id_to_toaster_layer_id[index.layerBranches[id].layer_id]),
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500187 release=release
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600188 )
189 except KeyError:
190 logger.warning(
191 "No such layerindex layer referenced by layerbranch %d" %
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800192 index.layerBranches[id].layer_id)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600193 continue
194
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500195 if created:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800196 lv.release = li_branch_id_to_toaster_release[index.layerBranches[id].branch_id]
197 lv.up_date = index.layerBranches[id].updated
198 lv.commit = index.layerBranches[id].actual_branch
199 lv.dirpath = index.layerBranches[id].vcs_subdir
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500200 lv.save()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600201
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800202 li_layer_branch_id_to_toaster_lv_id[index.layerBranches[id].id] =\
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600203 lv.pk
204 self.mini_progress("layer versions", i, total)
205
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800206 logger.info("Processing layer version dependencies")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600207
208 dependlist = {}
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800209 for id in index.layerDependencies:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600210 try:
211 lv = Layer_Version.objects.get(
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800212 pk=li_layer_branch_id_to_toaster_lv_id[index.layerDependencies[id].layerbranch_id])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600213 except Layer_Version.DoesNotExist as e:
214 continue
215
216 if lv not in dependlist:
217 dependlist[lv] = []
218 try:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800219 layer_id = li_layer_id_to_toaster_layer_id[index.layerDependencies[id].dependency_id]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600220
221 dependlist[lv].append(
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500222 Layer_Version.objects.get(layer__pk=layer_id,
223 release=lv.release))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600224
225 except Layer_Version.DoesNotExist:
226 logger.warning("Cannot find layer version (ls:%s),"
227 "up_id:%s lv:%s" %
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800228 (self, index.layerDependencies[id].dependency_id, lv))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600229
230 total = len(dependlist)
231 for i, lv in enumerate(dependlist):
232 LayerVersionDependency.objects.filter(layer_version=lv).delete()
233 for lvd in dependlist[lv]:
234 LayerVersionDependency.objects.get_or_create(layer_version=lv,
235 depends_on=lvd)
236 self.mini_progress("Layer version dependencies", i, total)
237
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500238 # update Distros
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800239 logger.info("Processing distro information")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500240
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800241 total = len(index.distros)
242 for i, id in enumerate(index.distros):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500243 distro, created = Distro.objects.get_or_create(
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800244 name=index.distros[id].name,
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500245 layer_version=Layer_Version.objects.get(
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800246 pk=li_layer_branch_id_to_toaster_lv_id[index.distros[id].layerbranch_id]))
247 distro.up_date = index.distros[id].updated
248 distro.name = index.distros[id].name
249 distro.description = index.distros[id].description
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500250 distro.save()
251 self.mini_progress("distros", i, total)
252
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600253 # update machines
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800254 logger.info("Processing machine information")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600255
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800256 total = len(index.machines)
257 for i, id in enumerate(index.machines):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600258 mo, created = Machine.objects.get_or_create(
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800259 name=index.machines[id].name,
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600260 layer_version=Layer_Version.objects.get(
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800261 pk=li_layer_branch_id_to_toaster_lv_id[index.machines[id].layerbranch_id]))
262 mo.up_date = index.machines[id].updated
263 mo.name = index.machines[id].name
264 mo.description = index.machines[id].description
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600265 mo.save()
266 self.mini_progress("machines", i, total)
267
268 # update recipes; paginate by layer version / layer branch
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800269 logger.info("Processing recipe information")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600270
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800271 total = len(index.recipes)
272 for i, id in enumerate(index.recipes):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600273 try:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800274 lv_id = li_layer_branch_id_to_toaster_lv_id[index.recipes[id].layerbranch_id]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600275 lv = Layer_Version.objects.get(pk=lv_id)
276
277 ro, created = Recipe.objects.get_or_create(
278 layer_version=lv,
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800279 name=index.recipes[id].pn
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600280 )
281
282 ro.layer_version = lv
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800283 ro.up_date = index.recipes[id].updated
284 ro.name = index.recipes[id].pn
285 ro.version = index.recipes[id].pv
286 ro.summary = index.recipes[id].summary
287 ro.description = index.recipes[id].description
288 ro.section = index.recipes[id].section
289 ro.license = index.recipes[id].license
290 ro.homepage = index.recipes[id].homepage
291 ro.bugtracker = index.recipes[id].bugtracker
292 ro.file_path = index.recipes[id].fullpath
293 ro.is_image = 'image' in index.recipes[id].inherits.split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600294 ro.save()
295 except Exception as e:
296 logger.warning("Failed saving recipe %s", e)
297
298 self.mini_progress("recipes", i, total)
299
300 os.system('setterm -cursor on')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500301
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500302 def handle(self, **options):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600303 self.update()