summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastermain
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2025-11-07 13:31:53 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2025-11-07 13:31:53 +0000
commit8c22ff0d8b70d9b12f0487ef696a7e915b9e3173 (patch)
treeefdc32587159d0050a69009bdf2330a531727d95 /bitbake/lib/toaster/toastermain
parentd412d2747595c1cc4a5e3ca975e3adc31b2f7891 (diff)
downloadpoky-8c22ff0d8b70d9b12f0487ef696a7e915b9e3173.tar.gz
The poky repository master branch is no longer being updated.
You can either: a) switch to individual clones of bitbake, openembedded-core, meta-yocto and yocto-docs b) use the new bitbake-setup You can find information about either approach in our documentation: https://docs.yoctoproject.org/ Note that "poky" the distro setting is still available in meta-yocto as before and we continue to use and maintain that. Long live Poky! Some further information on the background of this change can be found in: https://lists.openembedded.org/g/openembedded-architecture/message/2179 Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/toastermain')
-rw-r--r--bitbake/lib/toaster/toastermain/__init__.py0
-rw-r--r--bitbake/lib/toaster/toastermain/logs.py158
-rw-r--r--bitbake/lib/toaster/toastermain/management/__init__.py0
-rw-r--r--bitbake/lib/toaster/toastermain/management/commands/__init__.py0
-rw-r--r--bitbake/lib/toaster/toastermain/management/commands/builddelete.py60
-rw-r--r--bitbake/lib/toaster/toastermain/management/commands/buildimport.py579
-rw-r--r--bitbake/lib/toaster/toastermain/management/commands/buildslist.py16
-rw-r--r--bitbake/lib/toaster/toastermain/management/commands/checksocket.py57
-rw-r--r--bitbake/lib/toaster/toastermain/management/commands/perf.py62
-rw-r--r--bitbake/lib/toaster/toastermain/settings.py347
-rw-r--r--bitbake/lib/toaster/toastermain/settings_production_example.py45
-rw-r--r--bitbake/lib/toaster/toastermain/settings_test.py28
-rw-r--r--bitbake/lib/toaster/toastermain/urls.py82
-rw-r--r--bitbake/lib/toaster/toastermain/wsgi.py36
14 files changed, 0 insertions, 1470 deletions
diff --git a/bitbake/lib/toaster/toastermain/__init__.py b/bitbake/lib/toaster/toastermain/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
--- a/bitbake/lib/toaster/toastermain/__init__.py
+++ /dev/null
diff --git a/bitbake/lib/toaster/toastermain/logs.py b/bitbake/lib/toaster/toastermain/logs.py
deleted file mode 100644
index 62d871963a..0000000000
--- a/bitbake/lib/toaster/toastermain/logs.py
+++ /dev/null
@@ -1,158 +0,0 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4import os
5import logging
6import json
7from pathlib import Path
8from django.http import HttpRequest
9
10BUILDDIR = Path(os.environ.get('BUILDDIR', '/tmp'))
11
12def log_api_request(request, response, view, logger_name='api'):
13 """Helper function for LogAPIMixin"""
14
15 repjson = {
16 'view': view,
17 'path': request.path,
18 'method': request.method,
19 'status': response.status_code
20 }
21
22 logger = logging.getLogger(logger_name)
23 logger.info(
24 json.dumps(repjson, indent=4, separators=(", ", " : "))
25 )
26
27
28def log_view_mixin(view):
29 def log_view_request(*args, **kwargs):
30 # get request from args else kwargs
31 request = None
32 if len(args) > 0:
33 for req in args:
34 if isinstance(req, HttpRequest):
35 request = req
36 break
37 elif request is None:
38 request = kwargs.get('request')
39
40 response = view(*args, **kwargs)
41 view_name = 'unknown'
42 if hasattr(request, 'resolver_match'):
43 if hasattr(request.resolver_match, 'view_name'):
44 view_name = request.resolver_match.view_name
45
46 log_api_request(
47 request, response, view_name, 'toaster')
48 return response
49 return log_view_request
50
51
52
53class LogAPIMixin:
54 """Logs API requests
55
56 tested with:
57 - APIView
58 - ModelViewSet
59 - ReadOnlyModelViewSet
60 - GenericAPIView
61
62 Note: you can set `view_name` attribute in View to override get_view_name()
63 """
64
65 def get_view_name(self):
66 if hasattr(self, 'view_name'):
67 return self.view_name
68 return super().get_view_name()
69
70 def finalize_response(self, request, response, *args, **kwargs):
71 log_api_request(request, response, self.get_view_name())
72 return super().finalize_response(request, response, *args, **kwargs)
73
74
75LOGGING_SETTINGS = {
76 'version': 1,
77 'disable_existing_loggers': False,
78 'filters': {
79 'require_debug_false': {
80 '()': 'django.utils.log.RequireDebugFalse'
81 }
82 },
83 'formatters': {
84 'datetime': {
85 'format': '%(asctime)s %(levelname)s %(message)s'
86 },
87 'verbose': {
88 'format': '{levelname} {asctime} {module} {name}.{funcName} {process:d} {thread:d} {message}',
89 'datefmt': "%d/%b/%Y %H:%M:%S",
90 'style': '{',
91 },
92 'api': {
93 'format': '\n{levelname} {asctime} {name}.{funcName}:\n{message}',
94 'style': '{'
95 }
96 },
97 'handlers': {
98 'mail_admins': {
99 'level': 'ERROR',
100 'filters': ['require_debug_false'],
101 'class': 'django.utils.log.AdminEmailHandler'
102 },
103 'console': {
104 'level': 'DEBUG',
105 'class': 'logging.StreamHandler',
106 'formatter': 'datetime',
107 },
108 'file_django': {
109 'level': 'INFO',
110 'class': 'logging.handlers.TimedRotatingFileHandler',
111 'filename': BUILDDIR / 'toaster_logs/django.log',
112 'when': 'D', # interval type
113 'interval': 1, # defaults to 1
114 'backupCount': 10, # how many files to keep
115 'formatter': 'verbose',
116 },
117 'file_api': {
118 'level': 'INFO',
119 'class': 'logging.handlers.TimedRotatingFileHandler',
120 'filename': BUILDDIR / 'toaster_logs/api.log',
121 'when': 'D',
122 'interval': 1,
123 'backupCount': 10,
124 'formatter': 'verbose',
125 },
126 'file_toaster': {
127 'level': 'INFO',
128 'class': 'logging.handlers.TimedRotatingFileHandler',
129 'filename': BUILDDIR / 'toaster_logs/web.log',
130 'when': 'D',
131 'interval': 1,
132 'backupCount': 10,
133 'formatter': 'verbose',
134 },
135 },
136 'loggers': {
137 'django.request': {
138 'handlers': ['file_django', 'console'],
139 'level': 'WARN',
140 'propagate': True,
141 },
142 'django': {
143 'handlers': ['file_django', 'console'],
144 'level': 'WARNING',
145 'propogate': True,
146 },
147 'toaster': {
148 'handlers': ['file_toaster'],
149 'level': 'INFO',
150 'propagate': False,
151 },
152 'api': {
153 'handlers': ['file_api'],
154 'level': 'INFO',
155 'propagate': False,
156 }
157 }
158}
diff --git a/bitbake/lib/toaster/toastermain/management/__init__.py b/bitbake/lib/toaster/toastermain/management/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
--- a/bitbake/lib/toaster/toastermain/management/__init__.py
+++ /dev/null
diff --git a/bitbake/lib/toaster/toastermain/management/commands/__init__.py b/bitbake/lib/toaster/toastermain/management/commands/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
--- a/bitbake/lib/toaster/toastermain/management/commands/__init__.py
+++ /dev/null
diff --git a/bitbake/lib/toaster/toastermain/management/commands/builddelete.py b/bitbake/lib/toaster/toastermain/management/commands/builddelete.py
deleted file mode 100644
index 93919dec2d..0000000000
--- a/bitbake/lib/toaster/toastermain/management/commands/builddelete.py
+++ /dev/null
@@ -1,60 +0,0 @@
1#
2# SPDX-License-Identifier: GPL-2.0-only
3#
4
5from django.core.management.base import BaseCommand
6from django.core.exceptions import ObjectDoesNotExist
7from orm.models import Build
8from django.db import OperationalError
9
10
11class Command(BaseCommand):
12 args = '<buildID1 buildID2 .....>'
13 help = "Deletes selected build(s)"
14
15 def add_arguments(self, parser):
16 parser.add_argument('buildids', metavar='N', type=int, nargs='+',
17 help="Build ID's to delete")
18
19 def handle(self, *args, **options):
20 for bid in options['buildids']:
21 try:
22 b = Build.objects.get(pk = bid)
23 except ObjectDoesNotExist:
24 print('build %s does not exist, skipping...' %(bid))
25 continue
26 # theoretically, just b.delete() would suffice
27 # however SQLite runs into problems when you try to
28 # delete too many rows at once, so we delete some direct
29 # relationships from Build manually.
30 for t in b.target_set.all():
31 t.delete()
32 for t in b.task_build.all():
33 t.delete()
34 for p in b.package_set.all():
35 p.delete()
36 for lv in b.layer_version_build.all():
37 lv.delete()
38 for v in b.variable_build.all():
39 v.delete()
40 for l in b.logmessage_set.all():
41 l.delete()
42
43 # delete the build; some databases might have had problem with migration of the bldcontrol app
44 retry_count = 0
45 need_bldcontrol_migration = False
46 while True:
47 if retry_count >= 5:
48 break
49 retry_count += 1
50 if need_bldcontrol_migration:
51 from django.core import management
52 management.call_command('migrate', 'bldcontrol', interactive=False)
53
54 try:
55 b.delete()
56 break
57 except OperationalError as e:
58 # execute migrations
59 need_bldcontrol_migration = True
60
diff --git a/bitbake/lib/toaster/toastermain/management/commands/buildimport.py b/bitbake/lib/toaster/toastermain/management/commands/buildimport.py
deleted file mode 100644
index f7139aa041..0000000000
--- a/bitbake/lib/toaster/toastermain/management/commands/buildimport.py
+++ /dev/null
@@ -1,579 +0,0 @@
1#
2# BitBake Toaster Implementation
3#
4# Copyright (C) 2018 Wind River Systems
5#
6# SPDX-License-Identifier: GPL-2.0-only
7#
8
9# buildimport: import a project for project specific configuration
10#
11# Usage:
12# (a) Set up Toaster environent
13#
14# (b) Call buildimport
15# $ /path/to/bitbake/lib/toaster/manage.py buildimport \
16# --name=$PROJECTNAME \
17# --path=$BUILD_DIRECTORY \
18# --callback="$CALLBACK_SCRIPT" \
19# --command="configure|reconfigure|import"
20#
21# (c) Return is "|Default_image=%s|Project_id=%d"
22#
23# (d) Open Toaster to this project using for example:
24# $ xdg-open http://localhost:$toaster_port/toastergui/project_specific/$project_id
25#
26# (e) To delete a project:
27# $ /path/to/bitbake/lib/toaster/manage.py buildimport \
28# --name=$PROJECTNAME --delete-project
29#
30
31
32# ../bitbake/lib/toaster/manage.py buildimport --name=test --path=`pwd` --callback="" --command=import
33
34from django.core.management.base import BaseCommand
35from orm.models import Project, Release, ProjectVariable
36from orm.models import Layer, Layer_Version, LayerSource, ProjectLayer
37from toastergui.api import scan_layer_content
38
39import os
40import re
41import os.path
42import subprocess
43import shutil
44
45# Toaster variable section delimiters
46TOASTER_PROLOG = '#=== TOASTER_CONFIG_PROLOG ==='
47TOASTER_EPILOG = '#=== TOASTER_CONFIG_EPILOG ==='
48
49# quick development/debugging support
50verbose = 2
51def _log(msg):
52 if 1 == verbose:
53 print(msg)
54 elif 2 == verbose:
55 f1=open('/tmp/toaster.log', 'a')
56 f1.write("|" + msg + "|\n" )
57 f1.close()
58
59
60__config_regexp__ = re.compile( r"""
61 ^
62 (?P<exp>export\s+)?
63 (?P<var>[a-zA-Z0-9\-_+.${}/~]+?)
64 (\[(?P<flag>[a-zA-Z0-9\-_+.]+)\])?
65
66 \s* (
67 (?P<colon>:=) |
68 (?P<lazyques>\?\?=) |
69 (?P<ques>\?=) |
70 (?P<append>\+=) |
71 (?P<prepend>=\+) |
72 (?P<predot>=\.) |
73 (?P<postdot>\.=) |
74 =
75 ) \s*
76
77 (?!'[^']*'[^']*'$)
78 (?!\"[^\"]*\"[^\"]*\"$)
79 (?P<apo>['\"])
80 (?P<value>.*)
81 (?P=apo)
82 $
83 """, re.X)
84
85class Command(BaseCommand):
86 args = "<name> <path> <release>"
87 help = "Import a command line build directory"
88 vars = {}
89 toaster_vars = {}
90
91 def add_arguments(self, parser):
92 parser.add_argument(
93 '--name', dest='name', required=True,
94 help='name of the project',
95 )
96 parser.add_argument(
97 '--path', dest='path', required=True,
98 help='path to the project',
99 )
100 parser.add_argument(
101 '--release', dest='release', required=False,
102 help='release for the project',
103 )
104 parser.add_argument(
105 '--callback', dest='callback', required=False,
106 help='callback for project config update',
107 )
108 parser.add_argument(
109 '--delete-project', dest='delete_project', required=False,
110 help='delete this project from the database',
111 )
112 parser.add_argument(
113 '--command', dest='command', required=False,
114 help='command (configure,reconfigure,import)',
115 )
116
117 def get_var(self, varname):
118 value = self.vars.get(varname, '')
119 if value:
120 varrefs = re.findall('\${([^}]*)}', value)
121 for ref in varrefs:
122 if ref in self.vars:
123 value = value.replace('${%s}' % ref, self.vars[ref])
124 return value
125
126 # Extract the bb variables from a conf file
127 def scan_conf(self,fn):
128 vars = self.vars
129 toaster_vars = self.toaster_vars
130
131 #_log("scan_conf:%s" % fn)
132 if not os.path.isfile(fn):
133 return
134 f = open(fn, 'r')
135
136 #statements = ast.StatementGroup()
137 lineno = 0
138 is_toaster_section = False
139 while True:
140 lineno = lineno + 1
141 s = f.readline()
142 if not s:
143 break
144 w = s.strip()
145 # skip empty lines
146 if not w:
147 continue
148 # evaluate Toaster sections
149 if w.startswith(TOASTER_PROLOG):
150 is_toaster_section = True
151 continue
152 if w.startswith(TOASTER_EPILOG):
153 is_toaster_section = False
154 continue
155 s = s.rstrip()
156 while s[-1] == '\\':
157 s2 = f.readline().strip()
158 lineno = lineno + 1
159 if (not s2 or s2 and s2[0] != "#") and s[0] == "#" :
160 echo("There is a confusing multiline, partially commented expression on line %s of file %s (%s).\nPlease clarify whether this is all a comment or should be parsed." % (lineno, fn, s))
161 s = s[:-1] + s2
162 # skip comments
163 if s[0] == '#':
164 continue
165 # process the line for just assignments
166 m = __config_regexp__.match(s)
167 if m:
168 groupd = m.groupdict()
169 var = groupd['var']
170 value = groupd['value']
171
172 if groupd['lazyques']:
173 if not var in vars:
174 vars[var] = value
175 continue
176 if groupd['ques']:
177 if not var in vars:
178 vars[var] = value
179 continue
180 # preset empty blank for remaining operators
181 if not var in vars:
182 vars[var] = ''
183 if groupd['append']:
184 vars[var] += value
185 elif groupd['prepend']:
186 vars[var] = "%s%s" % (value,vars[var])
187 elif groupd['predot']:
188 vars[var] = "%s %s" % (value,vars[var])
189 elif groupd['postdot']:
190 vars[var] = "%s %s" % (vars[var],value)
191 else:
192 vars[var] = "%s" % (value)
193 # capture vars in a Toaster section
194 if is_toaster_section:
195 toaster_vars[var] = vars[var]
196
197 # DONE WITH PARSING
198 f.close()
199 self.vars = vars
200 self.toaster_vars = toaster_vars
201
202 # Update the scanned project variables
203 def update_project_vars(self,project,name):
204 pv, create = ProjectVariable.objects.get_or_create(project = project, name = name)
205 if (not name in self.vars.keys()) or (not self.vars[name]):
206 self.vars[name] = pv.value
207 else:
208 if pv.value != self.vars[name]:
209 pv.value = self.vars[name]
210 pv.save()
211
212 # Find the git version of the installation
213 def find_layer_dir_version(self,path):
214 # * rocko ...
215
216 install_version = ''
217 cwd = os.getcwd()
218 os.chdir(path)
219 p = subprocess.Popen(['git', 'branch', '-av'], stdout=subprocess.PIPE,
220 stderr=subprocess.PIPE)
221 out, err = p.communicate()
222 out = out.decode("utf-8")
223 for branch in out.split('\n'):
224 if ('*' == branch[0:1]) and ('no branch' not in branch):
225 install_version = re.sub(' .*','',branch[2:])
226 break
227 if 'remotes/m/master' in branch:
228 install_version = re.sub('.*base/','',branch)
229 break
230 os.chdir(cwd)
231 return install_version
232
233 # Compute table of the installation's registered layer versions (branch or commit)
234 def find_layer_dir_versions(self,INSTALL_URL_PREFIX):
235 lv_dict = {}
236 layer_versions = Layer_Version.objects.all()
237 for lv in layer_versions:
238 layer = Layer.objects.filter(pk=lv.layer.pk)[0]
239 if layer.vcs_url:
240 url_short = layer.vcs_url.replace(INSTALL_URL_PREFIX,'')
241 else:
242 url_short = ''
243 # register the core, branch, and the version variations
244 lv_dict["%s,%s,%s" % (url_short,lv.dirpath,'')] = (lv.id,layer.name)
245 lv_dict["%s,%s,%s" % (url_short,lv.dirpath,lv.branch)] = (lv.id,layer.name)
246 lv_dict["%s,%s,%s" % (url_short,lv.dirpath,lv.commit)] = (lv.id,layer.name)
247 #_log(" (%s,%s,%s|%s) = (%s,%s)" % (url_short,lv.dirpath,lv.branch,lv.commit,lv.id,layer.name))
248 return lv_dict
249
250 # Apply table of all layer versions
251 def extract_bblayers(self):
252 # set up the constants
253 bblayer_str = self.get_var('BBLAYERS')
254 TOASTER_DIR = os.environ.get('TOASTER_DIR')
255 INSTALL_CLONE_PREFIX = os.path.dirname(TOASTER_DIR) + "/"
256 TOASTER_CLONE_PREFIX = TOASTER_DIR + "/_toaster_clones/"
257 INSTALL_URL_PREFIX = ''
258 layers = Layer.objects.filter(name='openembedded-core')
259 for layer in layers:
260 if layer.vcs_url:
261 INSTALL_URL_PREFIX = layer.vcs_url
262 break
263 INSTALL_URL_PREFIX = INSTALL_URL_PREFIX.replace("/poky","/")
264 INSTALL_VERSION_DIR = TOASTER_DIR
265 INSTALL_URL_POSTFIX = INSTALL_URL_PREFIX.replace(':','_')
266 INSTALL_URL_POSTFIX = INSTALL_URL_POSTFIX.replace('/','_')
267 INSTALL_URL_POSTFIX = "%s_%s" % (TOASTER_CLONE_PREFIX,INSTALL_URL_POSTFIX)
268
269 # get the set of available layer:layer_versions
270 lv_dict = self.find_layer_dir_versions(INSTALL_URL_PREFIX)
271
272 # compute the layer matches
273 layers_list = []
274 for line in bblayer_str.split(' '):
275 if not line:
276 continue
277 if line.endswith('/local'):
278 continue
279
280 # isolate the repo
281 layer_path = line
282 line = line.replace(INSTALL_URL_POSTFIX,'').replace(INSTALL_CLONE_PREFIX,'').replace('/layers/','/').replace('/poky/','/')
283
284 # isolate the sub-path
285 path_index = line.rfind('/')
286 if path_index > 0:
287 sub_path = line[path_index+1:]
288 line = line[0:path_index]
289 else:
290 sub_path = ''
291
292 # isolate the version
293 if TOASTER_CLONE_PREFIX in layer_path:
294 is_toaster_clone = True
295 # extract version from name syntax
296 version_index = line.find('_')
297 if version_index > 0:
298 version = line[version_index+1:]
299 line = line[0:version_index]
300 else:
301 version = ''
302 _log("TOASTER_CLONE(%s/%s), version=%s" % (line,sub_path,version))
303 else:
304 is_toaster_clone = False
305 # version is from the installation
306 version = self.find_layer_dir_version(layer_path)
307 _log("LOCAL_CLONE(%s/%s), version=%s" % (line,sub_path,version))
308
309 # capture the layer information into layers_list
310 layers_list.append( (line,sub_path,version,layer_path,is_toaster_clone) )
311 return layers_list,lv_dict
312
313 #
314 def find_import_release(self,layers_list,lv_dict,default_release):
315 # poky,meta,rocko => 4;openembedded-core
316 release = default_release
317 for line,path,version,layer_path,is_toaster_clone in layers_list:
318 key = "%s,%s,%s" % (line,path,version)
319 if key in lv_dict:
320 lv_id = lv_dict[key]
321 if 'openembedded-core' == lv_id[1]:
322 _log("Find_import_release(%s):version=%s,Toaster=%s" % (lv_id[1],version,is_toaster_clone))
323 # only versions in Toaster managed layers are accepted
324 if not is_toaster_clone:
325 break
326 try:
327 release = Release.objects.get(name=version)
328 except:
329 pass
330 break
331 _log("Find_import_release:RELEASE=%s" % release.name)
332 return release
333
334 # Apply the found conf layers
335 def apply_conf_bblayers(self,layers_list,lv_dict,project,release=None):
336 for line,path,version,layer_path,is_toaster_clone in layers_list:
337 # Assert release promote if present
338 if release:
339 version = release
340 # try to match the key to a layer_version
341 key = "%s,%s,%s" % (line,path,version)
342 key_short = "%s,%s,%s" % (line,path,'')
343 lv_id = ''
344 if key in lv_dict:
345 lv_id = lv_dict[key]
346 lv = Layer_Version.objects.get(pk=int(lv_id[0]))
347 pl,created = ProjectLayer.objects.get_or_create(project=project,
348 layercommit=lv)
349 pl.optional=False
350 pl.save()
351 _log(" %s => %s;%s" % (key,lv_id[0],lv_id[1]))
352 elif key_short in lv_dict:
353 lv_id = lv_dict[key_short]
354 lv = Layer_Version.objects.get(pk=int(lv_id[0]))
355 pl,created = ProjectLayer.objects.get_or_create(project=project,
356 layercommit=lv)
357 pl.optional=False
358 pl.save()
359 _log(" %s ?> %s" % (key,lv_dict[key_short]))
360 else:
361 _log("%s <= %s" % (key,layer_path))
362 found = False
363 # does local layer already exist in this project?
364 try:
365 for pl in ProjectLayer.objects.filter(project=project):
366 if pl.layercommit.layer.local_source_dir == layer_path:
367 found = True
368 _log(" Project Local Layer found!")
369 except Exception as e:
370 _log("ERROR: Local Layer '%s'" % e)
371 pass
372
373 if not found:
374 # Does Layer name+path already exist?
375 try:
376 layer_name_base = os.path.basename(layer_path)
377 _log("Layer_lookup: try '%s','%s'" % (layer_name_base,layer_path))
378 layer = Layer.objects.get(name=layer_name_base,local_source_dir = layer_path)
379 # Found! Attach layer_version and ProjectLayer
380 layer_version = Layer_Version.objects.create(
381 layer=layer,
382 project=project,
383 layer_source=LayerSource.TYPE_IMPORTED)
384 layer_version.save()
385 pl,created = ProjectLayer.objects.get_or_create(project=project,
386 layercommit=layer_version)
387 pl.optional=False
388 pl.save()
389 found = True
390 # add layer contents to this layer version
391 scan_layer_content(layer,layer_version)
392 _log(" Parent Local Layer found in db!")
393 except Exception as e:
394 _log("Layer_exists_test_failed: Local Layer '%s'" % e)
395 pass
396
397 if not found:
398 # Insure that layer path exists, in case of user typo
399 if not os.path.isdir(layer_path):
400 _log("ERROR:Layer path '%s' not found" % layer_path)
401 continue
402 # Add layer to db and attach project to it
403 layer_name_base = os.path.basename(layer_path)
404 # generate a unique layer name
405 layer_name_matches = {}
406 for layer in Layer.objects.filter(name__contains=layer_name_base):
407 layer_name_matches[layer.name] = '1'
408 layer_name_idx = 0
409 layer_name_test = layer_name_base
410 while layer_name_test in layer_name_matches.keys():
411 layer_name_idx += 1
412 layer_name_test = "%s_%d" % (layer_name_base,layer_name_idx)
413 # create the layer and layer_verion objects
414 layer = Layer.objects.create(name=layer_name_test)
415 layer.local_source_dir = layer_path
416 layer_version = Layer_Version.objects.create(
417 layer=layer,
418 project=project,
419 layer_source=LayerSource.TYPE_IMPORTED)
420 layer.save()
421 layer_version.save()
422 pl,created = ProjectLayer.objects.get_or_create(project=project,
423 layercommit=layer_version)
424 pl.optional=False
425 pl.save()
426 # register the layer's content
427 _log(" Local Layer Add content")
428 scan_layer_content(layer,layer_version)
429 _log(" Local Layer Added '%s'!" % layer_name_test)
430
431 # Scan the project's conf files (if any)
432 def scan_conf_variables(self,project_path):
433 self.vars['TOPDIR'] = project_path
434 # scan the project's settings, add any new layers or variables
435 if os.path.isfile("%s/conf/local.conf" % project_path):
436 self.scan_conf("%s/conf/local.conf" % project_path)
437 self.scan_conf("%s/conf/bblayers.conf" % project_path)
438 # Import then disable old style Toaster conf files (before 'merged_attr')
439 old_toaster_local = "%s/conf/toaster.conf" % project_path
440 if os.path.isfile(old_toaster_local):
441 self.scan_conf(old_toaster_local)
442 shutil.move(old_toaster_local, old_toaster_local+"_old")
443 old_toaster_layer = "%s/conf/toaster-bblayers.conf" % project_path
444 if os.path.isfile(old_toaster_layer):
445 self.scan_conf(old_toaster_layer)
446 shutil.move(old_toaster_layer, old_toaster_layer+"_old")
447
448 # Scan the found conf variables (if any)
449 def apply_conf_variables(self,project,layers_list,lv_dict,release=None):
450 if self.vars:
451 # Catch vars relevant to Toaster (in case no Toaster section)
452 self.update_project_vars(project,'DISTRO')
453 self.update_project_vars(project,'MACHINE')
454 self.update_project_vars(project,'IMAGE_INSTALL:append')
455 self.update_project_vars(project,'IMAGE_FSTYPES')
456 self.update_project_vars(project,'PACKAGE_CLASSES')
457 # These vars are typically only assigned by Toaster
458 #self.update_project_vars(project,'DL_DIR')
459 #self.update_project_vars(project,'SSTATE_DIR')
460
461 # Assert found Toaster vars
462 for var in self.toaster_vars.keys():
463 pv, create = ProjectVariable.objects.get_or_create(project = project, name = var)
464 pv.value = self.toaster_vars[var]
465 _log("* Add/update Toaster var '%s' = '%s'" % (pv.name,pv.value))
466 pv.save()
467
468 # Assert found BBLAYERS
469 if 0 < verbose:
470 for pl in ProjectLayer.objects.filter(project=project):
471 release_name = 'None' if not pl.layercommit.release else pl.layercommit.release.name
472 print(" BEFORE:ProjectLayer=%s,%s,%s,%s" % (pl.layercommit.layer.name,release_name,pl.layercommit.branch,pl.layercommit.commit))
473 self.apply_conf_bblayers(layers_list,lv_dict,project,release)
474 if 0 < verbose:
475 for pl in ProjectLayer.objects.filter(project=project):
476 release_name = 'None' if not pl.layercommit.release else pl.layercommit.release.name
477 print(" AFTER :ProjectLayer=%s,%s,%s,%s" % (pl.layercommit.layer.name,release_name,pl.layercommit.branch,pl.layercommit.commit))
478
479 def handle(self, *args, **options):
480 project_name = options['name']
481 project_path = options['path']
482 project_callback = options['callback'] if options['callback'] else ''
483 release_name = options['release'] if options['release'] else ''
484
485 #
486 # Delete project
487 #
488
489 if options['delete_project']:
490 try:
491 print("Project '%s' delete from Toaster database" % (project_name))
492 project = Project.objects.get(name=project_name)
493 # TODO: deep project delete
494 project.delete()
495 print("Project '%s' Deleted" % (project_name))
496 return
497 except Exception as e:
498 print("Project '%s' not found, not deleted (%s)" % (project_name,e))
499 return
500
501 #
502 # Create/Update/Import project
503 #
504
505 # See if project (by name) exists
506 project = None
507 try:
508 # Project already exists
509 project = Project.objects.get(name=project_name)
510 except Exception as e:
511 pass
512
513 # Find the installation's default release
514 default_release = Release.objects.get(id=1)
515
516 # SANITY: if 'reconfig' but project does not exist (deleted externally), switch to 'import'
517 if ("reconfigure" == options['command']) and project is None:
518 options['command'] = 'import'
519
520 # 'Configure':
521 if "configure" == options['command']:
522 # Note: ignore any existing conf files
523 # create project, SANITY: reuse any project of same name
524 project = Project.objects.create_project(project_name,default_release,project)
525
526 # 'Re-configure':
527 if "reconfigure" == options['command']:
528 # Scan the directory's conf files
529 self.scan_conf_variables(project_path)
530 # Scan the layer list
531 layers_list,lv_dict = self.extract_bblayers()
532 # Apply any new layers or variables
533 self.apply_conf_variables(project,layers_list,lv_dict)
534
535 # 'Import':
536 if "import" == options['command']:
537 # Scan the directory's conf files
538 self.scan_conf_variables(project_path)
539 # Remove these Toaster controlled variables
540 for var in ('DL_DIR','SSTATE_DIR'):
541 self.vars.pop(var, None)
542 self.toaster_vars.pop(var, None)
543 # Scan the layer list
544 layers_list,lv_dict = self.extract_bblayers()
545 # Find the directory's release, and promote to default_release if local paths
546 release = self.find_import_release(layers_list,lv_dict,default_release)
547 # create project, SANITY: reuse any project of same name
548 project = Project.objects.create_project(project_name,release,project, imported=True)
549 # Apply any new layers or variables
550 self.apply_conf_variables(project,layers_list,lv_dict,release)
551 # WORKAROUND: since we now derive the release, redirect 'newproject_specific' to 'project_specific'
552 project.set_variable('INTERNAL_PROJECT_SPECIFIC_SKIPRELEASE','1')
553
554 # Set up the project's meta data
555 project.builddir = project_path
556 project.merged_attr = True
557 project.set_variable(Project.PROJECT_SPECIFIC_CALLBACK,project_callback)
558 project.set_variable(Project.PROJECT_SPECIFIC_STATUS,Project.PROJECT_SPECIFIC_EDIT)
559 if ("configure" == options['command']) or ("import" == options['command']):
560 # preset the mode and default image recipe
561 project.set_variable(Project.PROJECT_SPECIFIC_ISNEW,Project.PROJECT_SPECIFIC_NEW)
562 project.set_variable(Project.PROJECT_SPECIFIC_DEFAULTIMAGE,"core-image-minimal")
563
564 # Assert any extended/custom actions or variables for new non-Toaster projects
565 if not len(self.toaster_vars):
566 pass
567 else:
568 project.set_variable(Project.PROJECT_SPECIFIC_ISNEW,Project.PROJECT_SPECIFIC_NONE)
569
570 # Save the updated Project
571 project.save()
572
573 _log("Buildimport:project='%s' at '%d'" % (project_name,project.id))
574
575 if ('DEFAULT_IMAGE' in self.vars) and (self.vars['DEFAULT_IMAGE']):
576 print("|Default_image=%s|Project_id=%d" % (self.vars['DEFAULT_IMAGE'],project.id))
577 else:
578 print("|Project_id=%d" % (project.id))
579
diff --git a/bitbake/lib/toaster/toastermain/management/commands/buildslist.py b/bitbake/lib/toaster/toastermain/management/commands/buildslist.py
deleted file mode 100644
index 3ad5289c5e..0000000000
--- a/bitbake/lib/toaster/toastermain/management/commands/buildslist.py
+++ /dev/null
@@ -1,16 +0,0 @@
1#
2# SPDX-License-Identifier: GPL-2.0-only
3#
4
5from django.core.management.base import BaseCommand
6from orm.models import Build
7
8
9
10class Command(BaseCommand):
11 args = ""
12 help = "Lists current builds"
13
14 def handle(self,**options):
15 for b in Build.objects.all():
16 print("%d: %s %s %s" % (b.pk, b.machine, b.distro, ",".join([x.target for x in b.target_set.all()])))
diff --git a/bitbake/lib/toaster/toastermain/management/commands/checksocket.py b/bitbake/lib/toaster/toastermain/management/commands/checksocket.py
deleted file mode 100644
index b2c002da7a..0000000000
--- a/bitbake/lib/toaster/toastermain/management/commands/checksocket.py
+++ /dev/null
@@ -1,57 +0,0 @@
1#!/usr/bin/env python3
2#
3# BitBake Toaster Implementation
4#
5# Copyright (C) 2015 Intel Corporation
6#
7# SPDX-License-Identifier: GPL-2.0-only
8#
9
10"""Custom management command checksocket."""
11
12import errno
13import socket
14
15from django.core.management.base import BaseCommand, CommandError
16from django.utils.encoding import force_str
17
18DEFAULT_ADDRPORT = "0.0.0.0:8000"
19
20class Command(BaseCommand):
21 """Custom management command."""
22
23 help = 'Check if Toaster can listen on address:port'
24
25 def add_arguments(self, parser):
26 parser.add_argument('addrport', nargs='?', default=DEFAULT_ADDRPORT,
27 help='ipaddr:port to check, %s by default' % \
28 DEFAULT_ADDRPORT)
29
30 def handle(self, *args, **options):
31 addrport = options['addrport']
32 if ':' not in addrport:
33 raise CommandError('Invalid addr:port specified: %s' % addrport)
34 splitted = addrport.split(':')
35 try:
36 splitted[1] = int(splitted[1])
37 except ValueError:
38 raise CommandError('Invalid port specified: %s' % splitted[1])
39 self.stdout.write('Check if toaster can listen on %s' % addrport)
40 try:
41 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
42 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
43 sock.bind(tuple(splitted))
44 except (socket.error, OverflowError) as err:
45 errors = {
46 errno.EACCES: 'You don\'t have permission to access port %s' \
47 % splitted[1],
48 errno.EADDRINUSE: 'Port %s is already in use' % splitted[1],
49 errno.EADDRNOTAVAIL: 'IP address can\'t be assigned to',
50 }
51 if hasattr(err, 'errno') and err.errno in errors:
52 errtext = errors[err.errno]
53 else:
54 errtext = force_str(err)
55 raise CommandError(errtext)
56
57 self.stdout.write("OK")
diff --git a/bitbake/lib/toaster/toastermain/management/commands/perf.py b/bitbake/lib/toaster/toastermain/management/commands/perf.py
deleted file mode 100644
index 5c41c5b2f2..0000000000
--- a/bitbake/lib/toaster/toastermain/management/commands/perf.py
+++ /dev/null
@@ -1,62 +0,0 @@
1#
2# SPDX-License-Identifier: GPL-2.0-only
3#
4
5from django.core.management.base import BaseCommand
6from django.test.client import Client
7import os, sys, re
8import requests
9from django.conf import settings
10
11# pylint: disable=E1103
12# Instance of 'WSGIRequest' has no 'status_code' member
13# (but some types could not be inferred) (maybe-no-member)
14
15
16class Command(BaseCommand):
17 help = "Test the response time for all toaster urls"
18
19 def handle(self, *args, **options):
20 root_urlconf = __import__(settings.ROOT_URLCONF)
21 patterns = root_urlconf.urls.urlpatterns
22 global full_url
23 for pat in patterns:
24 if pat.__class__.__name__ == 'RegexURLResolver':
25 url_root_res = str(pat).split('^')[1].replace('>', '')
26 if 'gui' in url_root_res:
27 for url_patt in pat.url_patterns:
28 full_url = self.get_full_url(url_patt, url_root_res)
29 info = self.url_info(full_url)
30 status_code = info[0]
31 load_time = info[1]
32 print('Trying \'' + full_url + '\', ' + str(status_code) + ', ' + str(load_time))
33
34 def get_full_url(self, url_patt, url_root_res):
35 full_url = str(url_patt).split('^')[1].replace('$>', '').replace('(?P<file_path>(?:/[', '/bin/busybox').replace('.*', '')
36 full_url = str(url_root_res + full_url)
37 full_url = re.sub('\(\?P<.*?>\\\d\+\)', '1', full_url)
38 full_url = 'http://localhost:8000/' + full_url
39 return full_url
40
41 def url_info(self, full_url):
42 client = Client()
43 info = []
44 try:
45 resp = client.get(full_url, follow = True)
46 except Exception as e_status_code:
47 self.error('Url: %s, error: %s' % (full_url, e_status_code))
48 resp = type('object', (), {'status_code':0, 'content': str(e_status_code)})
49 status_code = resp.status_code
50 info.append(status_code)
51 try:
52 req = requests.get(full_url)
53 except Exception as e_load_time:
54 self.error('Url: %s, error: %s' % (full_url, e_load_time))
55 load_time = req.elapsed
56 info.append(load_time)
57 return info
58
59 def error(self, *args):
60 for arg in args:
61 print(arg, end=' ', file=sys.stderr)
62 print(file=sys.stderr)
diff --git a/bitbake/lib/toaster/toastermain/settings.py b/bitbake/lib/toaster/toastermain/settings.py
deleted file mode 100644
index d2a449627f..0000000000
--- a/bitbake/lib/toaster/toastermain/settings.py
+++ /dev/null
@@ -1,347 +0,0 @@
1#
2# BitBake Toaster Implementation
3#
4# Copyright (C) 2013 Intel Corporation
5#
6# SPDX-License-Identifier: GPL-2.0-only
7#
8
9# Django settings for Toaster project.
10
11import os
12from pathlib import Path
13from toastermain.logs import LOGGING_SETTINGS
14
15DEBUG = True
16
17# Set to True to see the SQL queries in console
18SQL_DEBUG = False
19if os.environ.get("TOASTER_SQLDEBUG", None) is not None:
20 SQL_DEBUG = True
21
22
23ADMINS = (
24 # ('Your Name', 'your_email@example.com'),
25)
26
27MANAGERS = ADMINS
28
29TOASTER_SQLITE_DEFAULT_DIR = os.environ.get('TOASTER_DIR')
30
31DATABASES = {
32 'default': {
33 # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
34 'ENGINE': 'django.db.backends.sqlite3',
35 # DB name or full path to database file if using sqlite3.
36 'NAME': "%s/toaster.sqlite" % TOASTER_SQLITE_DEFAULT_DIR,
37 'USER': '',
38 'PASSWORD': '',
39 #'HOST': '127.0.0.1', # e.g. mysql server
40 #'PORT': '3306', # e.g. mysql port
41 }
42}
43
44# New in Django 3.2
45DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
46
47# Needed when Using sqlite especially to add a longer timeout for waiting
48# for the database lock to be released
49# https://docs.djangoproject.com/en/1.6/ref/databases/#database-is-locked-errors
50if 'sqlite' in DATABASES['default']['ENGINE']:
51 DATABASES['default']['OPTIONS'] = { 'timeout': 20 }
52
53# Update as of django 1.8.16 release, the '*' is needed to allow us to connect while running
54# on hosts without explicitly setting the fqdn for the toaster server.
55# See https://docs.djangoproject.com/en/dev/ref/settings/ for info on ALLOWED_HOSTS
56# Previously this setting was not enforced if DEBUG was set but it is now.
57# The previous behavior was such that ALLOWED_HOSTS defaulted to ['localhost','127.0.0.1','::1']
58# and if you bound to 0.0.0.0:<port #> then accessing toaster as localhost or fqdn would both work.
59# To have that same behavior, with a fqdn explicitly enabled you would set
60# ALLOWED_HOSTS= ['localhost','127.0.0.1','::1','myserver.mycompany.com'] for
61# Django >= 1.8.16. By default, we are not enforcing this restriction in
62# DEBUG mode.
63if DEBUG is True:
64 # this will allow connection via localhost,hostname, or fqdn
65 ALLOWED_HOSTS = ['*']
66
67# Local time zone for this installation. Choices can be found here:
68# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
69# although not all choices may be available on all operating systems.
70# In a Windows environment this must be set to your system time zone.
71
72# Always use local computer's time zone, find
73import hashlib
74if 'TZ' in os.environ:
75 TIME_ZONE = os.environ['TZ']
76else:
77 # need to read the /etc/localtime file which is the libc standard
78 # and do a reverse-mapping to /usr/share/zoneinfo/;
79 # since the timezone may match any number of identical timezone definitions,
80
81 zonefilelist = {}
82 ZONEINFOPATH = '/usr/share/zoneinfo/'
83 for dirpath, dirnames, filenames in os.walk(ZONEINFOPATH):
84 for fn in filenames:
85 filepath = os.path.join(dirpath, fn)
86 zonename = filepath.lstrip(ZONEINFOPATH).strip()
87 try:
88 import pytz
89 from pytz.exceptions import UnknownTimeZoneError
90 try:
91 if pytz.timezone(zonename) is not None:
92 with open(filepath, 'rb') as f:
93 zonefilelist[hashlib.md5(f.read()).hexdigest()] = zonename
94 except UnknownTimeZoneError as ValueError:
95 # we expect timezone failures here, just move over
96 pass
97 except ImportError:
98 with open(filepath, 'rb') as f:
99 zonefilelist[hashlib.md5(f.read()).hexdigest()] = zonename
100
101 with open('/etc/localtime', 'rb') as f:
102 TIME_ZONE = zonefilelist[hashlib.md5(f.read()).hexdigest()]
103
104# Language code for this installation. All choices can be found here:
105# http://www.i18nguy.com/unicode/language-identifiers.html
106LANGUAGE_CODE = 'en-us'
107
108SITE_ID = 1
109
110# If you set this to False, Django will make some optimizations so as not
111# to load the internationalization machinery.
112USE_I18N = True
113
114# If you set this to False, Django will not use timezone-aware datetimes.
115USE_TZ = True
116
117# Absolute filesystem path to the directory that will hold user-uploaded files.
118# Example: "/var/www/example.com/media/"
119MEDIA_ROOT = ''
120
121# URL that handles the media served from MEDIA_ROOT. Make sure to use a
122# trailing slash.
123# Examples: "http://example.com/media/", "http://media.example.com/"
124MEDIA_URL = ''
125
126# Absolute path to the directory static files should be collected to.
127# Don't put anything in this directory yourself; store your static files
128# in apps' "static/" subdirectories and in STATICFILES_DIRS.
129# Example: "/var/www/example.com/static/"
130STATIC_ROOT = ''
131
132# URL prefix for static files.
133# Example: "http://example.com/static/", "http://static.example.com/"
134STATIC_URL = '/static/'
135
136# Additional locations of static files
137STATICFILES_DIRS = (
138 # Put strings here, like "/home/html/static" or "C:/www/django/static".
139 # Always use forward slashes, even on Windows.
140 # Don't forget to use absolute paths, not relative paths.
141)
142
143# List of finder classes that know how to find static files in
144# various locations.
145STATICFILES_FINDERS = (
146 'django.contrib.staticfiles.finders.FileSystemFinder',
147 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
148# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
149)
150
151# Make this unique, and don't share it with anybody.
152SECRET_KEY = 'NOT_SUITABLE_FOR_HOSTED_DEPLOYMENT'
153
154TMPDIR = os.environ.get('TOASTER_DJANGO_TMPDIR', '/tmp')
155
156class InvalidString(str):
157 def __mod__(self, other):
158 from django.template.base import TemplateSyntaxError
159 raise TemplateSyntaxError(
160 "Undefined variable or unknown value for: \"%s\"" % other)
161
162TEMPLATES = [
163 {
164 'BACKEND': 'django.template.backends.django.DjangoTemplates',
165 'DIRS': [
166 # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
167 # Always use forward slashes, even on Windows.
168 # Don't forget to use absolute paths, not relative paths.
169 ],
170 'OPTIONS': {
171 'context_processors': [
172 # Insert your TEMPLATE_CONTEXT_PROCESSORS here or use this
173 # list if you haven't customized them:
174 'django.contrib.auth.context_processors.auth',
175 'django.template.context_processors.debug',
176 'django.template.context_processors.i18n',
177 'django.template.context_processors.media',
178 'django.template.context_processors.static',
179 'django.template.context_processors.tz',
180 'django.contrib.messages.context_processors.messages',
181 # Custom
182 'django.template.context_processors.request',
183 'toastergui.views.managedcontextprocessor',
184
185 ],
186 'loaders': [
187 # List of callables that know how to import templates from various sources.
188 'django.template.loaders.filesystem.Loader',
189 'django.template.loaders.app_directories.Loader',
190 #'django.template.loaders.eggs.Loader',
191 ],
192 # https://docs.djangoproject.com/en/4.2/ref/templates/api/#how-invalid-variables-are-handled
193 # Generally, string_if_invalid should only be enabled in order to debug
194 # a specific template problem, then cleared once debugging is complete.
195 # If you assign a value other than '' to string_if_invalid,
196 # you will experience rendering problems with these templates and sites.
197 # 'string_if_invalid': InvalidString("%s"),
198 'string_if_invalid': "",
199 'debug': DEBUG,
200 },
201 },
202]
203
204MIDDLEWARE = [
205 'django.middleware.common.CommonMiddleware',
206 'django.contrib.sessions.middleware.SessionMiddleware',
207 'django.middleware.csrf.CsrfViewMiddleware',
208 'django.contrib.auth.middleware.AuthenticationMiddleware',
209 'django.contrib.messages.middleware.MessageMiddleware',
210 'django.contrib.auth.middleware.AuthenticationMiddleware',
211 'django.contrib.messages.middleware.MessageMiddleware',
212 'django.contrib.sessions.middleware.SessionMiddleware',
213]
214
215CACHES = {
216 # 'default': {
217 # 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
218 # 'LOCATION': '127.0.0.1:11211',
219 # },
220 'default': {
221 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
222 'LOCATION': '%s/toaster_cache_%d' % (TMPDIR, os.getuid()),
223 'TIMEOUT': 1,
224 }
225 }
226
227
228from os.path import dirname as DN
229SITE_ROOT=DN(DN(os.path.abspath(__file__)))
230
231import subprocess
232TOASTER_BRANCH = subprocess.Popen('git branch | grep "^* " | tr -d "* "', cwd = SITE_ROOT, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
233TOASTER_REVISION = subprocess.Popen('git rev-parse HEAD ', cwd = SITE_ROOT, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
234
235ROOT_URLCONF = 'toastermain.urls'
236
237# Python dotted path to the WSGI application used by Django's runserver.
238WSGI_APPLICATION = 'toastermain.wsgi.application'
239
240
241INSTALLED_APPS = (
242 'django.contrib.auth',
243 'django.contrib.contenttypes',
244 'django.contrib.messages',
245 'django.contrib.sessions',
246 'django.contrib.admin',
247 'django.contrib.staticfiles',
248
249 # Uncomment the next line to enable admin documentation:
250 # 'django.contrib.admindocs',
251 'django.contrib.humanize',
252 'bldcollector',
253 'toastermain',
254
255 # 3rd-lib
256 "log_viewer",
257)
258
259
260INTERNAL_IPS = ['127.0.0.1', '192.168.2.28']
261
262# Load django-fresh is TOASTER_DEVEL is set, and the module is available
263FRESH_ENABLED = False
264if os.environ.get('TOASTER_DEVEL', None) is not None:
265 try:
266 import fresh
267 MIDDLEWARE = ["fresh.middleware.FreshMiddleware",] + MIDDLEWARE
268 INSTALLED_APPS = INSTALLED_APPS + ('fresh',)
269 FRESH_ENABLED = True
270 except:
271 pass
272
273DEBUG_PANEL_ENABLED = False
274if os.environ.get('TOASTER_DEVEL', None) is not None:
275 try:
276 import debug_toolbar, debug_panel
277 MIDDLEWARE = ['debug_panel.middleware.DebugPanelMiddleware',] + MIDDLEWARE
278 #MIDDLEWARE = MIDDLEWARE + ['debug_toolbar.middleware.DebugToolbarMiddleware',]
279 INSTALLED_APPS = INSTALLED_APPS + ('debug_toolbar','debug_panel',)
280 DEBUG_PANEL_ENABLED = True
281
282 # this cache backend will be used by django-debug-panel
283 CACHES['debug-panel'] = {
284 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
285 'LOCATION': '/var/tmp/debug-panel-cache',
286 'TIMEOUT': 300,
287 'OPTIONS': {
288 'MAX_ENTRIES': 200
289 }
290 }
291
292 except:
293 pass
294
295
296SOUTH_TESTS_MIGRATE = False
297
298
299# We automatically detect and install applications here if
300# they have a 'models.py' or 'views.py' file
301currentdir = os.path.dirname(__file__)
302for t in os.walk(os.path.dirname(currentdir)):
303 modulename = os.path.basename(t[0])
304 #if we have a virtualenv skip it to avoid incorrect imports
305 if 'VIRTUAL_ENV' in os.environ and os.environ['VIRTUAL_ENV'] in t[0]:
306 continue
307
308 if ("views.py" in t[2] or "models.py" in t[2]) and not modulename in INSTALLED_APPS:
309 INSTALLED_APPS = INSTALLED_APPS + (modulename,)
310
311# A sample logging configuration. The only tangible logging
312# performed by this configuration is to send an email to
313# the site admins on every HTTP 500 error when DEBUG=False.
314# See http://docs.djangoproject.com/en/dev/topics/logging for
315# more details on how to customize your logging configuration.
316LOGGING = LOGGING_SETTINGS
317
318# Build paths inside the project like this: BASE_DIR / 'subdir'.
319BUILDDIR = os.environ.get("BUILDDIR", TMPDIR)
320
321# LOG VIEWER
322# https://pypi.org/project/django-log-viewer/
323LOG_VIEWER_FILES_PATTERN = '*.log*'
324LOG_VIEWER_FILES_DIR = os.path.join(BUILDDIR, "toaster_logs/")
325LOG_VIEWER_PAGE_LENGTH = 25 # total log lines per-page
326LOG_VIEWER_MAX_READ_LINES = 100000 # total log lines will be read
327LOG_VIEWER_PATTERNS = ['INFO', 'DEBUG', 'WARNING', 'ERROR', 'CRITICAL']
328
329# Optionally you can set the next variables in order to customize the admin:
330LOG_VIEWER_FILE_LIST_TITLE = "Logs list"
331
332if DEBUG and SQL_DEBUG:
333 LOGGING['loggers']['django.db.backends'] = {
334 'level': 'DEBUG',
335 'handlers': ['console'],
336 }
337
338
339# If we're using sqlite, we need to tweak the performance a bit
340from django.db.backends.signals import connection_created
341def activate_synchronous_off(sender, connection, **kwargs):
342 if connection.vendor == 'sqlite':
343 cursor = connection.cursor()
344 cursor.execute('PRAGMA synchronous = 0;')
345connection_created.connect(activate_synchronous_off)
346#
347
diff --git a/bitbake/lib/toaster/toastermain/settings_production_example.py b/bitbake/lib/toaster/toastermain/settings_production_example.py
deleted file mode 100644
index 6cd0f52dd7..0000000000
--- a/bitbake/lib/toaster/toastermain/settings_production_example.py
+++ /dev/null
@@ -1,45 +0,0 @@
1#
2# BitBake Toaster Implementation
3#
4# Copyright (C) 2016 Intel Corporation
5#
6# SPDX-License-Identifier: GPL-2.0-only
7#
8
9# See Django documentation for more information about deployment
10# https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
11
12# Toaster production settings example overlay
13# To use this copy this example to "settings_production.py" and set in your
14# environment DJANGO_SETTINGS_MODULE=toastermain.settings_production
15# This can be permanently set in a new .wsgi file
16
17from toastermain.settings import * # NOQA
18
19# Set this value!
20SECRET_KEY = None
21
22# Switch off any debugging
23DEBUG = True
24TEMPLATE_DEBUG = DEBUG
25
26DATABASES = {
27 'default': {
28 'ENGINE': 'django.db.backends.mysql',
29 'NAME': 'toaster_data',
30 'USER': 'toaster',
31 'PASSWORD': 'yourpasswordhere',
32 'HOST': '127.0.0.1',
33 'PORT': '3306',
34 }
35}
36
37# Location where static files will be placed by "manage.py collectstatic"
38STATIC_ROOT = '/var/www/static-toaster/'
39
40# URL prefix for static files.
41STATIC_URL = '/static-toaster/'
42
43# Hosts that Django will serve
44# https://docs.djangoproject.com/en/1.8/ref/settings/#std:setting-ALLOWED_HOSTS
45ALLOWED_HOSTS = ['toaster-example.example.com']
diff --git a/bitbake/lib/toaster/toastermain/settings_test.py b/bitbake/lib/toaster/toastermain/settings_test.py
deleted file mode 100644
index 74def2d240..0000000000
--- a/bitbake/lib/toaster/toastermain/settings_test.py
+++ /dev/null
@@ -1,28 +0,0 @@
1#
2# BitBake Toaster Implementation
3#
4# Copyright (C) 2016 Intel Corporation
5#
6# SPDX-License-Identifier: GPL-2.0-only
7#
8
9# Django settings for Toaster project.
10
11# Settings overlay to use for running tests
12# DJANGO_SETTINGS_MODULE=toastermain.settings-test
13
14from toastermain.settings import *
15
16DEBUG = True
17TEMPLATE_DEBUG = DEBUG
18
19DATABASES = {
20 'default': {
21 'ENGINE': 'django.db.backends.sqlite3',
22 'NAME': '%s/toaster-test-db.sqlite' % TMPDIR,
23 'TEST': {
24 'ENGINE': 'django.db.backends.sqlite3',
25 'NAME': '%s/toaster-test-db.sqlite' % TMPDIR,
26 }
27 }
28}
diff --git a/bitbake/lib/toaster/toastermain/urls.py b/bitbake/lib/toaster/toastermain/urls.py
deleted file mode 100644
index 3be46fcf0c..0000000000
--- a/bitbake/lib/toaster/toastermain/urls.py
+++ /dev/null
@@ -1,82 +0,0 @@
1#
2# BitBake Toaster Implementation
3#
4# Copyright (C) 2013 Intel Corporation
5#
6# SPDX-License-Identifier: GPL-2.0-only
7#
8
9from django.urls import re_path as url, include
10from django.views.generic import RedirectView, TemplateView
11from django.views.decorators.cache import never_cache
12import bldcollector.views
13
14import logging
15
16logger = logging.getLogger("toaster")
17
18# Uncomment the next two lines to enable the admin:
19from django.contrib import admin
20admin.autodiscover()
21
22urlpatterns = [
23
24 # Examples:
25 # url(r'^toaster/', include('toaster.foo.urls')),
26
27 # Uncomment the admin/doc line below to enable admin documentation:
28 # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
29
30
31 url(r'^logs/', include('log_viewer.urls')),
32
33 # This is here to maintain backward compatibility and will be deprecated
34 # in the future.
35 url(r'^orm/eventfile$', bldcollector.views.eventfile),
36
37 url(r'^health$', TemplateView.as_view(template_name="health.html"), name='Toaster Health'),
38
39 # if no application is selected, we have the magic toastergui app here
40 url(r'^$', never_cache(RedirectView.as_view(url='/toastergui/', permanent=True))),
41]
42
43import toastermain.settings
44
45if toastermain.settings.FRESH_ENABLED:
46 urlpatterns.insert(1, url(r'', include('fresh.urls')))
47 #logger.info("Enabled django-fresh extension")
48
49if toastermain.settings.DEBUG_PANEL_ENABLED:
50 import debug_toolbar
51 urlpatterns.insert(1, url(r'', include(debug_toolbar.urls)))
52 #logger.info("Enabled django_toolbar extension")
53
54urlpatterns = [
55 # Uncomment the next line to enable the admin:
56 url(r'^admin/', admin.site.urls),
57] + urlpatterns
58
59# Automatically discover urls.py in various apps, beside our own
60# and map module directories to the patterns
61
62import os
63currentdir = os.path.dirname(__file__)
64for t in os.walk(os.path.dirname(currentdir)):
65 #if we have a virtualenv skip it to avoid incorrect imports
66 if 'VIRTUAL_ENV' in os.environ and os.environ['VIRTUAL_ENV'] in t[0]:
67 continue
68
69 if "urls.py" in t[2] and t[0] != currentdir:
70 modulename = os.path.basename(t[0])
71 # make sure we don't have this module name in
72 conflict = False
73 for p in urlpatterns:
74 if p.pattern.regex.pattern == '^' + modulename + '/':
75 conflict = True
76 if not conflict:
77 urlpatterns.insert(0, url(r'^' + modulename + '/', include ( modulename + '.urls')))
78 else:
79 logger.warning("Module \'%s\' has a regexp conflict, was not added to the urlpatterns" % modulename)
80
81from pprint import pformat
82#logger.debug("urlpatterns list %s", pformat(urlpatterns))
diff --git a/bitbake/lib/toaster/toastermain/wsgi.py b/bitbake/lib/toaster/toastermain/wsgi.py
deleted file mode 100644
index 4c31283279..0000000000
--- a/bitbake/lib/toaster/toastermain/wsgi.py
+++ /dev/null
@@ -1,36 +0,0 @@
1#
2# SPDX-License-Identifier: GPL-2.0-only
3#
4
5"""
6WSGI config for Toaster project.
7
8This module contains the WSGI application used by Django's development server
9and any production WSGI deployments. It should expose a module-level variable
10named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
11this application via the ``WSGI_APPLICATION`` setting.
12
13Usually you will have the standard Django WSGI application here, but it also
14might make sense to replace the whole Django WSGI application with a custom one
15that later delegates to the Django one. For example, you could introduce WSGI
16middleware here, or combine a Django application with an application of another
17framework.
18
19"""
20import os
21
22# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
23# if running multiple sites in the same mod_wsgi process. To fix this, use
24# mod_wsgi daemon mode with each site in its own daemon process, or use
25# os.environ["DJANGO_SETTINGS_MODULE"] = "Toaster.settings"
26os.environ.setdefault("DJANGO_SETTINGS_MODULE", "toastermain.settings")
27
28# This application object is used by any WSGI server configured to use this
29# file. This includes Django's development server, if the WSGI_APPLICATION
30# setting points here.
31from django.core.wsgi import get_wsgi_application
32application = get_wsgi_application()
33
34# Apply WSGI middleware here.
35# from helloworld.wsgi import HelloWorldApplication
36# application = HelloWorldApplication(application)