<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://bugzilla.yoctoproject.org/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.6"
          urlbase="https://bugzilla.yoctoproject.org/"
          
          maintainer="it-coreprojects-helpdesk@linuxfoundation.org"
>

    <bug>
          <bug_id>15332</bug_id>
          
          <creation_ts>2023-12-28 05:14:20 +0000</creation_ts>
          <short_desc>layerindex: Branch Comparison throws Internal Server Error</short_desc>
          <delta_ts>2026-10-18 02:20:18 +0000</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>6</classification_id>
          <classification>Yocto Project Subprojects</classification>
          <product>Layer Index</product>
          <component>Layer Index</component>
          <version>5.0</version>
          <rep_platform>x86</rep_platform>
          <op_sys>Multiple</op_sys>
          <bug_status>IN PROGRESS REVIEW</bug_status>
          <resolution></resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords></keywords>
          <priority>Medium+</priority>
          <bug_severity>major</bug_severity>
          <target_milestone>6.2 M1</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Tim Orling">tim.orling</reporter>
          <assigned_to name="Tim Orling">tim.orling</assigned_to>
          <cc>randy.macleod</cc>
          
          <qa_contact name="apoorv sangal">apoorvsangal</qa_contact>
          <cf_os>---</cf_os>
          <cf_regression_type>---</cf_regression_type>
          
          <cf_docchange>No (bug/feature does not impact docs)</cf_docchange>

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>97711</commentid>
    <comment_count>0</comment_count>
    <who name="Tim Orling">tim.orling</who>
    <bug_when>2023-12-28 05:14:20 +0000</bug_when>
    <thetext>If you try to compare e.g. &quot;master&quot; to &quot;nanbield&quot;, an Internal Server Error is thrown.

The debug output gives us a strong hint:

NameError at /layerindex/branch_comparison/
name &apos;parser_version&apos; is not defined
...
Traceback (most recent call last):
  File &quot;/usr/local/lib/python3.10/dist-packages/django/core/handlers/exception.py&quot;, line 55, in inner
    response = get_response(request)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/core/handlers/base.py&quot;, line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/views/generic/base.py&quot;, line 104, in view
    return self.dispatch(request, *args, **kwargs)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/views/generic/base.py&quot;, line 143, in dispatch
    return handler(request, *args, **kwargs)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/views/generic/edit.py&quot;, line 144, in get
    return self.render_to_response(self.get_context_data())
  File &quot;/opt/layerindex/layerindex/views.py&quot;, line 1850, in get_context_data
    context[&apos;added&apos;], context[&apos;changed&apos;], context[&apos;removed&apos;] = self.get_recipes(from_branch, to_branch, layer_ids)
  File &quot;/opt/layerindex/layerindex/views.py&quot;, line 1810, in get_recipes
    recipe.to_versions = sorted(recipe.to_versions, key=lambda item: parser_version(item.pv))
  File &quot;/opt/layerindex/layerindex/views.py&quot;, line 1810, in &lt;lambda&gt;
    recipe.to_versions = sorted(recipe.to_versions, key=lambda item: parser_version(item.pv))

Exception Type: NameError at /layerindex/branch_comparison/
Exception Value: name &apos;parser_version&apos; is not defined
Raised during: layerindex.views.BranchCompareView
...</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>97712</commentid>
    <comment_count>1</comment_count>
    <who name="Tim Orling">tim.orling</who>
    <bug_when>2023-12-28 05:19:40 +0000</bug_when>
    <thetext>The issue is a typo in:
https://git.yoctoproject.org/layerindex-web/tree/layerindex/views.py#n1794

recipe.to_versions = sorted(recipe.to_versions, key=lambda item: parser_version(item.pv))

Where parser_version should be parse_version.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>97717</commentid>
    <comment_count>2</comment_count>
    <who name="Tim Orling">tim.orling</who>
    <bug_when>2023-12-30 05:58:52 +0000</bug_when>
    <thetext>https://patchwork.yoctoproject.org/project/yocto/patch/01094d0e2a2c4f8df9feea877b2159677c642ab8.1703911977.git.tim.orling@konsulko.com/

This one was subtle. VSCode syntax highlighting is to be credited with actually catching the fix (although in hindsight the debug log was fairly obvious).</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>97731</commentid>
    <comment_count>3</comment_count>
    <who name="Tim Orling">tim.orling</who>
    <bug_when>2024-01-04 17:07:26 +0000</bug_when>
    <thetext>Fixed in:
https://git.yoctoproject.org/layerindex-web/commit/?id=a03b314bc1a0aea6f702c896a45a9e6376779569</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>98167</commentid>
    <comment_count>4</comment_count>
    <who name="Tim Orling">tim.orling</who>
    <bug_when>2024-02-09 00:33:27 +0000</bug_when>
    <thetext>If you try any other layer, such as meta-oe, you will still get an Internal Server Error:

Environment:


Request Method: GET
Request URL: http://&lt;local instance&gt;/layerindex/branch_comparison/?from_branch=29&amp;to_branch=1&amp;layers=2%2C1&amp;l=2&amp;l=1

Django Version: 4.2.9
Python Version: 3.10.12
Installed Applications:
(&apos;django.contrib.auth&apos;,
 &apos;django.contrib.contenttypes&apos;,
 &apos;django.contrib.sessions&apos;,
 &apos;django.contrib.sites&apos;,
 &apos;django.contrib.messages&apos;,
 &apos;django.contrib.staticfiles&apos;,
 &apos;django.contrib.admin&apos;,
 &apos;django.contrib.admindocs&apos;,
 &apos;layerindex&apos;,
 &apos;rrs&apos;,
 &apos;django_registration&apos;,
 &apos;reversion&apos;,
 &apos;reversion_compare&apos;,
 &apos;captcha&apos;,
 &apos;axes&apos;,
 &apos;rest_framework&apos;,
 &apos;corsheaders&apos;)
Installed Middleware:
(&apos;corsheaders.middleware.CorsMiddleware&apos;,
 &apos;django.middleware.common.CommonMiddleware&apos;,
 &apos;django.contrib.sessions.middleware.SessionMiddleware&apos;,
 &apos;django.middleware.csrf.CsrfViewMiddleware&apos;,
 &apos;django.contrib.auth.middleware.AuthenticationMiddleware&apos;,
 &apos;django.contrib.messages.middleware.MessageMiddleware&apos;,
 &apos;django.middleware.clickjacking.XFrameOptionsMiddleware&apos;,
 &apos;axes.middleware.AxesMiddleware&apos;,
 &apos;layerindex.middleware.NonAtomicRevisionMiddleware&apos;)



Traceback (most recent call last):
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/fields/__init__.py&quot;, line 2053, in get_prep_value
    return int(value)

The above exception (invalid literal for int() with base 10: &apos;,&apos;) was the direct cause of the following exception:
  File &quot;/usr/local/lib/python3.10/dist-packages/django/core/handlers/exception.py&quot;, line 55, in inner
    response = get_response(request)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/core/handlers/base.py&quot;, line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/views/generic/base.py&quot;, line 104, in view
    return self.dispatch(request, *args, **kwargs)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/views/generic/base.py&quot;, line 143, in dispatch
    return handler(request, *args, **kwargs)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/views/generic/edit.py&quot;, line 144, in get
    return self.render_to_response(self.get_context_data())
  File &quot;/opt/layerindex/layerindex/views.py&quot;, line 1875, in get_context_data
    context[&apos;added&apos;], context[&apos;changed&apos;], context[&apos;removed&apos;] = self.get_recipes(from_branch, to_branch, layer_ids)
  File &quot;/opt/layerindex/layerindex/views.py&quot;, line 1811, in get_recipes
    from_recipes = from_recipes.filter(layerbranch__layer__in=layer_ids)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/query.py&quot;, line 1436, in filter
    return self._filter_or_exclude(False, args, kwargs)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/query.py&quot;, line 1454, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/query.py&quot;, line 1461, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/sql/query.py&quot;, line 1546, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/sql/query.py&quot;, line 1577, in _add_q
    child_clause, needed_inner = self.build_filter(
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/sql/query.py&quot;, line 1492, in build_filter
    condition = self.build_lookup(lookups, col, value)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/sql/query.py&quot;, line 1319, in build_lookup
    lookup = lookup_class(lhs, rhs)
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/lookups.py&quot;, line 27, in __init__
    self.rhs = self.get_prep_lookup()
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/fields/related_lookups.py&quot;, line 92, in get_prep_lookup
    self.rhs = [target_field.get_prep_value(v) for v in self.rhs]
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/fields/related_lookups.py&quot;, line 92, in &lt;listcomp&gt;
    self.rhs = [target_field.get_prep_value(v) for v in self.rhs]
  File &quot;/usr/local/lib/python3.10/dist-packages/django/db/models/fields/__init__.py&quot;, line 2055, in get_prep_value
    raise e.__class__(

Exception Type: ValueError at /layerindex/branch_comparison/
Exception Value: Field &apos;id&apos; expected a number but got &apos;,&apos;.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>98168</commentid>
    <comment_count>5</comment_count>
    <who name="Tim Orling">tim.orling</who>
    <bug_when>2024-02-09 00:40:41 +0000</bug_when>
    <thetext>If you clear &apos;openembedded-core&apos; and add only &apos;meta-oe&apos; the comparison succeeds. So it looks like multiple selections are not being split() properly or something along those lines.

Successful:
https://layers.openembedded.org/layerindex/branch_comparison/?from_branch=29&amp;to_branch=1&amp;layers=2&amp;l=2

vs.

Failure:
https://layers.openembedded.org/layerindex/branch_comparison/?from_branch=29&amp;to_branch=1&amp;layers=2%2C1&amp;l=2&amp;l=1

So the way that URL is being combined is not being handled as expected.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>98169</commentid>
    <comment_count>6</comment_count>
    <who name="Tim Orling">tim.orling</who>
    <bug_when>2024-02-09 00:51:24 +0000</bug_when>
    <thetext>Also, for some reason, meta-ros2-humble cannot be compared from nanbield to master (even though both LayerBranches exist):

https://layers.openembedded.org/layerindex/branch_comparison/?from_branch=29&amp;to_branch=1&amp;layers=602&amp;l=602</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99538</commentid>
    <comment_count>7</comment_count>
    <who name="Tim Orling">tim.orling</who>
    <bug_when>2024-08-10 21:12:55 +0000</bug_when>
    <thetext>Something is wrong with the layer_id parsing, because if you hand code an url, like
https://layers.openembedded.org/layerindex/branch_comparison/?from_branch=14&amp;to_branch=30&amp;layers=2

It properly shows the changes from sumo to scarthgap for meta-oe (layer_id = 2).

If you click on the Plain Text button, you can see only one layer was selected:
&quot;
From sumo (Yocto Project 2.5) to scarthgap (Yocto Project 5.0) (layers: meta-oe)


Added
-----
abseil-cpp 20240116.2
ace 6.5.19
ace-cloud-editor 02.07.17+git
...
&quot;

If you choose any layer with more than 1 digit, such as meta-virtualization (which appears to be layer_id = 59) you instead see layer_id = 5 (e100-bsp) and layer_id = 9 (meta-gumstix) chosen!

https://layers.openembedded.net/layerindex/branch_comparison/?from_branch=14&amp;to_branch=30&amp;layers=59

&quot;
From sumo (Yocto Project 2.5) to scarthgap (Yocto Project 5.0) (layers: e100-bsp, meta-gumstix)
...
&quot;

If you use the GUI to select only meta-virtualization in the filter, the resulting URL is:
https://layers.openembedded.net/layerindex/branch_comparison/?from_branch=14&amp;to_branch=30&amp;layers=59&amp;l=59

Which still resolves to the same two layers above (layer_id = 5 and layer_id = 9)

If you start with the default GUI (where oe-core is selected) and then add meta-virtualization, the resulting URL throws an Internal Server Error (expecting a layer_id and gets a &apos;,&apos;):

https://layers.moto-timo.net/layerindex/branch_comparison/?from_branch=14&amp;to_branch=30&amp;layers=59%2C1&amp;l=59&amp;l=1

So the drop down menu is not creating a proper URL, and more than single digit layer_id is not being parsed properly.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99546</commentid>
    <comment_count>8</comment_count>
    <who name="Tim Orling">tim.orling</who>
    <bug_when>2024-08-16 03:44:54 +0000</bug_when>
    <thetext>The answer is rather obvious in hindsight. If you want a list of items to iterate on, ask for a list. (self.request.GET.getlist NOT self.request.GET.get). The first gives you a list, the second gives you a string which if you iterate over it, you get char.

diff --git a/layerindex/views.py b/layerindex/views.py
index 49bda30..908dfe1 100644
--- a/layerindex/views.py
+++ b/layerindex/views.py
@@ -1858,7 +1858,7 @@ class BranchCompareView(FormView):
         to_branch_id = self.request.GET.get(&apos;to_branch&apos;, None)
         if to_branch_id is not None:
             initial[&apos;to_branch&apos;] = get_object_or_404(Branch, id=to_branch_id)
-        initial[&apos;layers&apos;] = self.request.GET.get(&apos;layers&apos;, int(LayerItem.objects.get(name=settings.CORE_LAYER_NAME).id))
+        initial[&apos;layers&apos;] = self.request.GET.getlist(&apos;layers&apos;, int(LayerItem.objects.get(name=settings.CORE_LAYER_NAME).id))
         logger.debug(f&quot;initial[&apos;layers&apos;]: {initial[&apos;layers&apos;]}&quot;)
         return initial

@@ -1867,7 +1867,7 @@ class BranchCompareView(FormView):
         from_branch_id = self.request.GET.get(&apos;from_branch&apos;, None)
         to_branch_id = self.request.GET.get(&apos;to_branch&apos;, None)

-        layer_ids = list(self.request.GET.get(&apos;layers&apos;, int(LayerItem.objects.get(name=settings.CORE_LAYER_NAME).id)))
+        layer_ids = self.request.GET.getlist(&apos;layers&apos;, int(LayerItem.objects.get(name=settings.CORE_LAYER_NAME).id))
         from_branch = None
         if from_branch_id is not None:
             from_branch = get_object_or_404(Branch, id=from_branch_id)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>107097</commentid>
    <comment_count>9</comment_count>
    <who name="Tim Orling">tim.orling</who>
    <bug_when>2026-10-18 02:20:18 +0000</bug_when>
    <thetext>https://lore.kernel.org/yocto-patches/20261017165703.70617-3-tim.orling@konsulko.com/</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>