summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake')
-rw-r--r--bitbake/doc/bitbake-user-manual/bitbake-user-manual-fetching.rst21
-rw-r--r--bitbake/doc/bitbake-user-manual/bitbake-user-manual-metadata.rst19
-rw-r--r--bitbake/doc/bitbake-user-manual/bitbake-user-manual-ref-variables.rst75
-rw-r--r--bitbake/lib/bb/fetch2/git.py6
-rw-r--r--bitbake/lib/bb/parse/ast.py16
-rw-r--r--bitbake/lib/bb/parse/parse_py/ConfHandler.py2
-rw-r--r--bitbake/lib/toaster/tests/browser/test_layerdetails_page.py2
-rw-r--r--bitbake/lib/toaster/tests/functional/test_project_page.py8
8 files changed, 117 insertions, 32 deletions
diff --git a/bitbake/doc/bitbake-user-manual/bitbake-user-manual-fetching.rst b/bitbake/doc/bitbake-user-manual/bitbake-user-manual-fetching.rst
index eac3cbdfb5..a2c2432db1 100644
--- a/bitbake/doc/bitbake-user-manual/bitbake-user-manual-fetching.rst
+++ b/bitbake/doc/bitbake-user-manual/bitbake-user-manual-fetching.rst
@@ -39,10 +39,10 @@ variable and then calls the ``download`` method to download the files.
39 39
40The instantiation of the fetch class is usually followed by:: 40The instantiation of the fetch class is usually followed by::
41 41
42 rootdir = l.getVar('WORKDIR') 42 rootdir = l.getVar('UNPACKDIR')
43 fetcher.unpack(rootdir) 43 fetcher.unpack(rootdir)
44 44
45This code unpacks the downloaded files to the specified by ``WORKDIR``. 45This code unpacks the downloaded files to the specified by ``UNPACKDIR``.
46 46
47.. note:: 47.. note::
48 48
@@ -51,7 +51,7 @@ This code unpacks the downloaded files to the specified by ``WORKDIR``.
51 examine the OpenEmbedded class file ``base.bbclass`` 51 examine the OpenEmbedded class file ``base.bbclass``
52 . 52 .
53 53
54The :term:`SRC_URI` and ``WORKDIR`` variables are not hardcoded into the 54The :term:`SRC_URI` and ``UNPACKDIR`` variables are not hardcoded into the
55fetcher, since those fetcher methods can be (and are) called with 55fetcher, since those fetcher methods can be (and are) called with
56different variable names. In OpenEmbedded for example, the shared state 56different variable names. In OpenEmbedded for example, the shared state
57(sstate) code uses the fetch module to fetch the sstate files. 57(sstate) code uses the fetch module to fetch the sstate files.
@@ -463,13 +463,6 @@ Here are some example URLs::
463 463
464.. note:: 464.. note::
465 465
466 When using ``git`` as the fetcher of the main source code of your software,
467 ``S`` should be set accordingly::
468
469 S = "${WORKDIR}/git"
470
471.. note::
472
473 Specifying passwords directly in ``git://`` urls is not supported. 466 Specifying passwords directly in ``git://`` urls is not supported.
474 There are several reasons: :term:`SRC_URI` is often written out to logs and 467 There are several reasons: :term:`SRC_URI` is often written out to logs and
475 other places, and that could easily leak passwords; it is also all too 468 other places, and that could easily leak passwords; it is also all too
@@ -598,7 +591,7 @@ and port, username, and password, and fetches the Head Revision::
598 SRC_URI = "p4://example-depot/main/source/..." 591 SRC_URI = "p4://example-depot/main/source/..."
599 SRCREV = "${AUTOREV}" 592 SRCREV = "${AUTOREV}"
600 PV = "p4-${SRCPV}" 593 PV = "p4-${SRCPV}"
601 S = "${WORKDIR}/p4" 594 S = "${UNPACKDIR}/p4"
602 595
603Here is an example that specifies the server URL and port, username, and 596Here is an example that specifies the server URL and port, username, and
604password, and fetches a Revision based on a Label:: 597password, and fetches a Revision based on a Label::
@@ -607,15 +600,15 @@ password, and fetches a Revision based on a Label::
607 SRC_URI = "p4://user:passwd@example-depot/main/source/..." 600 SRC_URI = "p4://user:passwd@example-depot/main/source/..."
608 SRCREV = "release-1.0" 601 SRCREV = "release-1.0"
609 PV = "p4-${SRCPV}" 602 PV = "p4-${SRCPV}"
610 S = "${WORKDIR}/p4" 603 S = "${UNPACKDIR}/p4"
611 604
612.. note:: 605.. note::
613 606
614 You should always set S to "${WORKDIR}/p4" in your recipe. 607 You should always set S to "${UNPACKDIR}/p4" in your recipe.
615 608
616By default, the fetcher strips the depot location from the local file paths. In 609By default, the fetcher strips the depot location from the local file paths. In
617the above example, the content of ``example-depot/main/source/`` will be placed 610the above example, the content of ``example-depot/main/source/`` will be placed
618in ``${WORKDIR}/p4``. For situations where preserving parts of the remote depot 611in ``${UNPACKDIR}/p4``. For situations where preserving parts of the remote depot
619paths locally is desirable, the fetcher supports two parameters: 612paths locally is desirable, the fetcher supports two parameters:
620 613
621- *"module":* 614- *"module":*
diff --git a/bitbake/doc/bitbake-user-manual/bitbake-user-manual-metadata.rst b/bitbake/doc/bitbake-user-manual/bitbake-user-manual-metadata.rst
index a27b7758d9..f60a9d8312 100644
--- a/bitbake/doc/bitbake-user-manual/bitbake-user-manual-metadata.rst
+++ b/bitbake/doc/bitbake-user-manual/bitbake-user-manual-metadata.rst
@@ -998,9 +998,9 @@ This directive allows fine-tuning local configurations with configuration
998snippets contained in layers in a structured, controlled way. Typically it would 998snippets contained in layers in a structured, controlled way. Typically it would
999go into ``bitbake.conf``, for example:: 999go into ``bitbake.conf``, for example::
1000 1000
1001 addfragments conf/fragments OE_FRAGMENTS OE_FRAGMENTS_METADATA_VARS 1001 addfragments conf/fragments OE_FRAGMENTS OE_FRAGMENTS_METADATA_VARS OE_BUILTIN_FRAGMENTS
1002 1002
1003``addfragments`` takes three parameters: 1003``addfragments`` takes four parameters:
1004 1004
1005- path prefix for fragment files inside the layer file tree that bitbake 1005- path prefix for fragment files inside the layer file tree that bitbake
1006 uses to construct full paths to the fragment files 1006 uses to construct full paths to the fragment files
@@ -1011,6 +1011,8 @@ go into ``bitbake.conf``, for example::
1011- name of variable that contains a list of variable names containing 1011- name of variable that contains a list of variable names containing
1012 fragment-specific metadata (such as descriptions) 1012 fragment-specific metadata (such as descriptions)
1013 1013
1014- name of variable that contains definitions for built-in fragments
1015
1014This allows listing enabled configuration fragments in ``OE_FRAGMENTS`` 1016This allows listing enabled configuration fragments in ``OE_FRAGMENTS``
1015variable like this:: 1017variable like this::
1016 1018
@@ -1035,6 +1037,19 @@ The implementation will add a flag containing the fragment name to each of those
1035when parsing fragments, so that the variables are namespaced by fragment name, and do not override 1037when parsing fragments, so that the variables are namespaced by fragment name, and do not override
1036each other when several fragments are enabled. 1038each other when several fragments are enabled.
1037 1039
1040The variable containing a built-in fragment definitions could look like this::
1041
1042 OE_BUILTIN_FRAGMENTS = "someprefix:SOMEVARIABLE anotherprefix:ANOTHERVARIABLE"
1043
1044and then if 'someprefix/somevalue' is added to the variable that holds the list
1045of enabled fragments:
1046
1047 OE_FRAGMENTS = "... someprefix/somevalue"
1048
1049bitbake will treat that as direct value assignment in its configuration::
1050
1051 SOMEVARIABLE = "somevalue"
1052
1038Functions 1053Functions
1039========= 1054=========
1040 1055
diff --git a/bitbake/doc/bitbake-user-manual/bitbake-user-manual-ref-variables.rst b/bitbake/doc/bitbake-user-manual/bitbake-user-manual-ref-variables.rst
index 477443e228..6be8dbbf63 100644
--- a/bitbake/doc/bitbake-user-manual/bitbake-user-manual-ref-variables.rst
+++ b/bitbake/doc/bitbake-user-manual/bitbake-user-manual-ref-variables.rst
@@ -310,6 +310,11 @@ overview of their function and contents.
310 310
311 For example usage, see :term:`BB_GIT_SHALLOW`. 311 For example usage, see :term:`BB_GIT_SHALLOW`.
312 312
313 :term:`BB_GIT_DEFAULT_DESTSUFFIX`
314 The default destination directory where the Git fetcher unpacks the
315 source code. If this variable is not set, the source code is unpacked in a
316 directory named "git".
317
313 :term:`BB_GIT_SHALLOW` 318 :term:`BB_GIT_SHALLOW`
314 Setting this variable to "1" enables the support for fetching, using and 319 Setting this variable to "1" enables the support for fetching, using and
315 generating mirror tarballs of `shallow git repositories <https://riptutorial.com/git/example/4584/shallow-clone>`_. 320 generating mirror tarballs of `shallow git repositories <https://riptutorial.com/git/example/4584/shallow-clone>`_.
@@ -533,11 +538,28 @@ overview of their function and contents.
533 version 4.20 expose under ``/proc/pressure``. The threshold represents 538 version 4.20 expose under ``/proc/pressure``. The threshold represents
534 the difference in "total" pressure from the previous second. The 539 the difference in "total" pressure from the previous second. The
535 minimum value is 1.0 (extremely slow builds) and the maximum is 540 minimum value is 1.0 (extremely slow builds) and the maximum is
536 1000000 (a pressure value unlikely to ever be reached). 541 1000000 (a pressure value unlikely to ever be reached). See
542 https://docs.kernel.org/accounting/psi.html for more information.
543
544 A default value to limit the CPU pressure to be set in ``conf/local.conf``
545 could be::
546
547 BB_PRESSURE_MAX_CPU = "15000"
548
549 Multiple values should be tested on the build host to determine what suits
550 best, depending on the need for performances versus load average during
551 the build.
552
553 .. note::
537 554
538 This threshold can be set in ``conf/local.conf`` as:: 555 You may see numerous messages printed by BitBake in the case the
556 :term:`BB_PRESSURE_MAX_CPU` is too low:
539 557
540 BB_PRESSURE_MAX_CPU = "500" 558 Pressure status changed to CPU: True, IO: False, Mem: False (CPU: 1105.9/2.0, IO: 0.0/2.0, Mem: 0.0/2.0) - using 1/64 bitbake threads
559
560 This means that the :term:`BB_PRESSURE_MAX_CPU` should be increased to
561 a reasonable value for limiting the CPU pressure on the system.
562 Monitor the varying value after ``IO:`` above to set a sensible value.
541 563
542 :term:`BB_PRESSURE_MAX_IO` 564 :term:`BB_PRESSURE_MAX_IO`
543 Specifies a maximum I/O pressure threshold, above which BitBake's 565 Specifies a maximum I/O pressure threshold, above which BitBake's
@@ -549,14 +571,34 @@ overview of their function and contents.
549 version 4.20 expose under ``/proc/pressure``. The threshold represents 571 version 4.20 expose under ``/proc/pressure``. The threshold represents
550 the difference in "total" pressure from the previous second. The 572 the difference in "total" pressure from the previous second. The
551 minimum value is 1.0 (extremely slow builds) and the maximum is 573 minimum value is 1.0 (extremely slow builds) and the maximum is
552 1000000 (a pressure value unlikely to ever be reached). 574 1000000 (a pressure value unlikely to ever be reached). See
575 https://docs.kernel.org/accounting/psi.html for more information.
553 576
554 At this point in time, experiments show that IO pressure tends to 577 At this point in time, experiments show that IO pressure tends to
555 be short-lived and regulating just the CPU with 578 be short-lived and regulating just the CPU with
556 :term:`BB_PRESSURE_MAX_CPU` can help to reduce it. 579 :term:`BB_PRESSURE_MAX_CPU` can help to reduce it.
557 580
558 :term:`BB_PRESSURE_MAX_MEMORY` 581 A default value to limit the IO pressure to be set in ``conf/local.conf``
582 could be::
583
584 BB_PRESSURE_MAX_IO = "15000"
585
586 Multiple values should be tested on the build host to determine what suits
587 best, depending on the need for performances versus I/O usage during the
588 build.
589
590 .. note::
559 591
592 You may see numerous messages printed by BitBake in the case the
593 :term:`BB_PRESSURE_MAX_IO` is too low::
594
595 Pressure status changed to CPU: None, IO: True, Mem: False (CPU: 2236.0/None, IO: 153.6/2.0, Mem: 0.0/2.0) - using 19/64 bitbake threads
596
597 This means that the :term:`BB_PRESSURE_MAX_IO` should be increased to
598 a reasonable value for limiting the I/O pressure on the system.
599 Monitor the varying value after ``IO:`` above to set a sensible value.
600
601 :term:`BB_PRESSURE_MAX_MEMORY`
560 Specifies a maximum memory pressure threshold, above which BitBake's 602 Specifies a maximum memory pressure threshold, above which BitBake's
561 scheduler will not start new tasks (providing there is at least 603 scheduler will not start new tasks (providing there is at least
562 one active task). If no value is set, memory pressure is not 604 one active task). If no value is set, memory pressure is not
@@ -566,7 +608,8 @@ overview of their function and contents.
566 version 4.20 expose under ``/proc/pressure``. The threshold represents 608 version 4.20 expose under ``/proc/pressure``. The threshold represents
567 the difference in "total" pressure from the previous second. The 609 the difference in "total" pressure from the previous second. The
568 minimum value is 1.0 (extremely slow builds) and the maximum is 610 minimum value is 1.0 (extremely slow builds) and the maximum is
569 1000000 (a pressure value unlikely to ever be reached). 611 1000000 (a pressure value unlikely to ever be reached). See
612 https://docs.kernel.org/accounting/psi.html for more information.
570 613
571 Memory pressure is experienced when time is spent swapping, 614 Memory pressure is experienced when time is spent swapping,
572 refaulting pages from the page cache or performing direct reclaim. 615 refaulting pages from the page cache or performing direct reclaim.
@@ -574,6 +617,26 @@ overview of their function and contents.
574 might be useful as a last resort to prevent OOM errors if they are 617 might be useful as a last resort to prevent OOM errors if they are
575 occurring during builds. 618 occurring during builds.
576 619
620 A default value to limit the memory pressure to be set in
621 ``conf/local.conf`` could be::
622
623 BB_PRESSURE_MAX_MEMORY = "15000"
624
625 Multiple values should be tested on the build host to determine what suits
626 best, depending on the need for performances versus memory consumption
627 during the build.
628
629 .. note::
630
631 You may see numerous messages printed by BitBake in the case the
632 :term:`BB_PRESSURE_MAX_MEMORY` is too low::
633
634 Pressure status changed to CPU: None, IO: False, Mem: True (CPU: 29.5/None, IO: 0.0/2.0, Mem: 2553.3/2.0) - using 17/64 bitbake threads
635
636 This means that the :term:`BB_PRESSURE_MAX_MEMORY` should be increased to
637 a reasonable value for limiting the memory pressure on the system.
638 Monitor the varying value after ``Mem:`` above to set a sensible value.
639
577 :term:`BB_RUNFMT` 640 :term:`BB_RUNFMT`
578 Specifies the name of the executable script files (i.e. run files) 641 Specifies the name of the executable script files (i.e. run files)
579 saved into ``${``\ :term:`T`\ ``}``. By default, the 642 saved into ``${``\ :term:`T`\ ``}``. By default, the
diff --git a/bitbake/lib/bb/fetch2/git.py b/bitbake/lib/bb/fetch2/git.py
index 55dd084abc..14ec45a3f6 100644
--- a/bitbake/lib/bb/fetch2/git.py
+++ b/bitbake/lib/bb/fetch2/git.py
@@ -199,6 +199,8 @@ class Git(FetchMethod):
199 ud.shallow_skip_fast = False 199 ud.shallow_skip_fast = False
200 ud.shallow = d.getVar("BB_GIT_SHALLOW") == "1" 200 ud.shallow = d.getVar("BB_GIT_SHALLOW") == "1"
201 ud.shallow_extra_refs = (d.getVar("BB_GIT_SHALLOW_EXTRA_REFS") or "").split() 201 ud.shallow_extra_refs = (d.getVar("BB_GIT_SHALLOW_EXTRA_REFS") or "").split()
202 if 'tag' in ud.parm:
203 ud.shallow_extra_refs.append("refs/tags/" + ud.parm['tag'])
202 204
203 depth_default = d.getVar("BB_GIT_SHALLOW_DEPTH") 205 depth_default = d.getVar("BB_GIT_SHALLOW_DEPTH")
204 if depth_default is not None: 206 if depth_default is not None:
@@ -633,8 +635,6 @@ class Git(FetchMethod):
633 for line in all_refs_remote: 635 for line in all_refs_remote:
634 all_refs.append(line.split()[-1]) 636 all_refs.append(line.split()[-1])
635 extra_refs = [] 637 extra_refs = []
636 if 'tag' in ud.parm:
637 extra_refs.append(ud.parm['tag'])
638 for r in ud.shallow_extra_refs: 638 for r in ud.shallow_extra_refs:
639 if not ud.bareclone: 639 if not ud.bareclone:
640 r = r.replace('refs/heads/', 'refs/remotes/origin/') 640 r = r.replace('refs/heads/', 'refs/remotes/origin/')
@@ -660,7 +660,7 @@ class Git(FetchMethod):
660 subdir = ud.parm.get("subdir") 660 subdir = ud.parm.get("subdir")
661 subpath = ud.parm.get("subpath") 661 subpath = ud.parm.get("subpath")
662 readpathspec = "" 662 readpathspec = ""
663 def_destsuffix = "git/" 663 def_destsuffix = (d.getVar("BB_GIT_DEFAULT_DESTSUFFIX") or "git") + "/"
664 664
665 if subpath: 665 if subpath:
666 readpathspec = ":%s" % subpath 666 readpathspec = ":%s" % subpath
diff --git a/bitbake/lib/bb/parse/ast.py b/bitbake/lib/bb/parse/ast.py
index ea1096f2de..49a0788038 100644
--- a/bitbake/lib/bb/parse/ast.py
+++ b/bitbake/lib/bb/parse/ast.py
@@ -343,11 +343,12 @@ class InheritDeferredNode(AstNode):
343 bb.parse.BBHandler.inherit_defer(*self.inherit, data) 343 bb.parse.BBHandler.inherit_defer(*self.inherit, data)
344 344
345class AddFragmentsNode(AstNode): 345class AddFragmentsNode(AstNode):
346 def __init__(self, filename, lineno, fragments_path_prefix, fragments_variable, flagged_variables_list_variable): 346 def __init__(self, filename, lineno, fragments_path_prefix, fragments_variable, flagged_variables_list_variable, builtin_fragments_variable):
347 AstNode.__init__(self, filename, lineno) 347 AstNode.__init__(self, filename, lineno)
348 self.fragments_path_prefix = fragments_path_prefix 348 self.fragments_path_prefix = fragments_path_prefix
349 self.fragments_variable = fragments_variable 349 self.fragments_variable = fragments_variable
350 self.flagged_variables_list_variable = flagged_variables_list_variable 350 self.flagged_variables_list_variable = flagged_variables_list_variable
351 self.builtin_fragments_variable = builtin_fragments_variable
351 352
352 def eval(self, data): 353 def eval(self, data):
353 # No need to use mark_dependency since we would only match a fragment 354 # No need to use mark_dependency since we would only match a fragment
@@ -360,13 +361,23 @@ class AddFragmentsNode(AstNode):
360 return candidate_fragment_path 361 return candidate_fragment_path
361 return None 362 return None
362 363
364 def check_and_set_builtin_fragment(fragment, data, builtin_fragments):
365 prefix, value = fragment.split('/', 1)
366 if prefix in builtin_fragments.keys():
367 data.setVar(builtin_fragments[prefix], value)
368 return True
369 return False
370
363 fragments = data.getVar(self.fragments_variable) 371 fragments = data.getVar(self.fragments_variable)
364 layers = data.getVar('BBLAYERS') 372 layers = data.getVar('BBLAYERS')
365 flagged_variables = data.getVar(self.flagged_variables_list_variable).split() 373 flagged_variables = data.getVar(self.flagged_variables_list_variable).split()
374 builtin_fragments = {f[0]:f[1] for f in [f.split(':') for f in data.getVar(self.builtin_fragments_variable).split()] }
366 375
367 if not fragments: 376 if not fragments:
368 return 377 return
369 for f in fragments.split(): 378 for f in fragments.split():
379 if check_and_set_builtin_fragment(f, data, builtin_fragments):
380 continue
370 layerid, fragment_name = f.split('/', 1) 381 layerid, fragment_name = f.split('/', 1)
371 full_fragment_name = data.expand("{}/{}.conf".format(self.fragments_path_prefix, fragment_name)) 382 full_fragment_name = data.expand("{}/{}.conf".format(self.fragments_path_prefix, fragment_name))
372 fragment_path = find_fragment(layers, layerid, full_fragment_name) 383 fragment_path = find_fragment(layers, layerid, full_fragment_name)
@@ -430,7 +441,8 @@ def handleAddFragments(statements, filename, lineno, m):
430 fragments_path_prefix = m.group(1) 441 fragments_path_prefix = m.group(1)
431 fragments_variable = m.group(2) 442 fragments_variable = m.group(2)
432 flagged_variables_list_variable = m.group(3) 443 flagged_variables_list_variable = m.group(3)
433 statements.append(AddFragmentsNode(filename, lineno, fragments_path_prefix, fragments_variable, flagged_variables_list_variable)) 444 builtin_fragments_variable = m.group(4)
445 statements.append(AddFragmentsNode(filename, lineno, fragments_path_prefix, fragments_variable, flagged_variables_list_variable, builtin_fragments_variable))
434 446
435def runAnonFuncs(d): 447def runAnonFuncs(d):
436 code = [] 448 code = []
diff --git a/bitbake/lib/bb/parse/parse_py/ConfHandler.py b/bitbake/lib/bb/parse/parse_py/ConfHandler.py
index 675838d845..9ddbae123d 100644
--- a/bitbake/lib/bb/parse/parse_py/ConfHandler.py
+++ b/bitbake/lib/bb/parse/parse_py/ConfHandler.py
@@ -48,7 +48,7 @@ __export_regexp__ = re.compile( r"export\s+([a-zA-Z0-9\-_+.${}/~]+)$" )
48__unset_regexp__ = re.compile( r"unset\s+([a-zA-Z0-9\-_+.${}/~]+)$" ) 48__unset_regexp__ = re.compile( r"unset\s+([a-zA-Z0-9\-_+.${}/~]+)$" )
49__unset_flag_regexp__ = re.compile( r"unset\s+([a-zA-Z0-9\-_+.${}/~]+)\[([a-zA-Z0-9\-_+.][a-zA-Z0-9\-_+.@]+)\]$" ) 49__unset_flag_regexp__ = re.compile( r"unset\s+([a-zA-Z0-9\-_+.${}/~]+)\[([a-zA-Z0-9\-_+.][a-zA-Z0-9\-_+.@]+)\]$" )
50__addpylib_regexp__ = re.compile(r"addpylib\s+(.+)\s+(.+)" ) 50__addpylib_regexp__ = re.compile(r"addpylib\s+(.+)\s+(.+)" )
51__addfragments_regexp__ = re.compile(r"addfragments\s+(.+)\s+(.+)\s+(.+)" ) 51__addfragments_regexp__ = re.compile(r"addfragments\s+(.+)\s+(.+)\s+(.+)\s+(.+)" )
52 52
53def init(data): 53def init(data):
54 return 54 return
diff --git a/bitbake/lib/toaster/tests/browser/test_layerdetails_page.py b/bitbake/lib/toaster/tests/browser/test_layerdetails_page.py
index 69493833f4..6abfdef699 100644
--- a/bitbake/lib/toaster/tests/browser/test_layerdetails_page.py
+++ b/bitbake/lib/toaster/tests/browser/test_layerdetails_page.py
@@ -108,6 +108,8 @@ class TestLayerDetailsPage(SeleniumTestCase):
108 save_btn.click() 108 save_btn.click()
109 109
110 self.wait_until_visible("#save-changes-for-switch") 110 self.wait_until_visible("#save-changes-for-switch")
111 # Ensure scrolled into view
112 self.driver.execute_script('window.scrollTo({behavior: "instant", top: 0, left: 0})')
111 btn_save_chg_for_switch = self.wait_until_clickable( 113 btn_save_chg_for_switch = self.wait_until_clickable(
112 "#save-changes-for-switch") 114 "#save-changes-for-switch")
113 btn_save_chg_for_switch.click() 115 btn_save_chg_for_switch.click()
diff --git a/bitbake/lib/toaster/tests/functional/test_project_page.py b/bitbake/lib/toaster/tests/functional/test_project_page.py
index c6dad0eb5d..429d86feba 100644
--- a/bitbake/lib/toaster/tests/functional/test_project_page.py
+++ b/bitbake/lib/toaster/tests/functional/test_project_page.py
@@ -685,17 +685,17 @@ class TestProjectPage(TestProjectPageBase):
685 'active', str(self.find('#information').get_attribute('class')) 685 'active', str(self.find('#information').get_attribute('class'))
686 ) 686 )
687 # Check second tab (recipes) 687 # Check second tab (recipes)
688 # Ensure page is scrolled to the top
689 self.driver.find_element(By.XPATH, '//body').send_keys(Keys.CONTROL + Keys.HOME)
690 self.wait_until_visible('.nav-tabs') 688 self.wait_until_visible('.nav-tabs')
689 # Ensure page is scrolled to the top
690 self.driver.execute_script('window.scrollTo({behavior: "instant", top: 0, left: 0})')
691 tabs[1].click() 691 tabs[1].click()
692 self.assertIn( 692 self.assertIn(
693 'active', str(self.find('#recipes').get_attribute('class')) 693 'active', str(self.find('#recipes').get_attribute('class'))
694 ) 694 )
695 # Check third tab (machines) 695 # Check third tab (machines)
696 # Ensure page is scrolled to the top
697 self.driver.find_element(By.XPATH, '//body').send_keys(Keys.CONTROL + Keys.HOME)
698 self.wait_until_visible('.nav-tabs') 696 self.wait_until_visible('.nav-tabs')
697 # Ensure page is scrolled to the top
698 self.driver.execute_script('window.scrollTo({behavior: "instant", top: 0, left: 0})')
699 tabs[2].click() 699 tabs[2].click()
700 self.assertIn( 700 self.assertIn(
701 'active', str(self.find('#machines').get_attribute('class')) 701 'active', str(self.find('#machines').get_attribute('class'))