@@ -108,39 +108,52 @@ def search_dnf(query: str, cache_manager: Optional[object] = None) -> List[Tuple
108108 return []
109109
110110 logger .debug ("Parsing DNF search results" )
111- # Parse DNF output
111+ # Parse DNF/DNF5 output. DNF5 may not emit explicit headers and can use tabs or
112+ # multiple spaces between package name and description. We avoid relying on a
113+ # header toggle and instead parse any reasonable package line.
112114 packages = []
113- in_results = False
114115 lines_processed = 0
115116
117+ arch_pattern = r"\.(x86_64|i686|armv7hl|aarch64|ppc64le|s390x|noarch)$"
118+
116119 for line in output .split ("\n " ):
117120 line = line .strip ()
118121 lines_processed += 1
119-
122+
120123 if not line :
121124 continue
122125
123- # Detect start of results section
124- if "====" in line or ("Name" in line and "Matched" in line ):
125- logger .debug ("Found DNF results section header" )
126- in_results = True
126+ # Skip meta/info lines
127+ lower_line = line .lower ()
128+ if lower_line .startswith ((
129+ "last metadata" ,
130+ "updating" ,
131+ "repositories" ,
132+ "matched fields" ,
133+ "error:" ,
134+ "warning:"
135+ )):
136+ continue
137+
138+ # DNF classic format: "name : description"
139+ match = re .match (r"^(\S+)\s*:\s*(.+)$" , line )
140+
141+ # DNF5 format often uses tabs or multiple spaces: "name<TAB>description"
142+ if not match :
143+ match = re .match (r"^(\S+)\s{2,}(.+)$" , line ) or re .match (r"^(\S+)\t+(.+)$" , line )
144+
145+ if match :
146+ name_version = match .group (1 ).strip ()
147+ desc = match .group (2 ).strip ()
148+
149+ # Remove architecture suffix (e.g., .x86_64, .noarch) if present
150+ name = re .sub (arch_pattern , "" , name_version )
151+
152+ packages .append ((name , desc , "dnf" ))
153+ logger .debug (f"Found DNF package: { name } " )
127154 continue
128155
129- # Process package lines
130- if in_results and line and not line .startswith ("Last metadata" ):
131- if " : " in line : # standard DNF format: "package : description"
132- parts = line .split (" : " , 1 )
133- if len (parts ) == 2 :
134- name_version = parts [0 ].strip ()
135- desc = parts [1 ].strip ()
136-
137- # Remove architecture suffix (e.g., .x86_64, .noarch) if present
138- arch_pattern = r"\.(x86_64|i686|armv7hl|aarch64|ppc64le|s390x|noarch)$"
139- name = re .sub (arch_pattern , "" , name_version )
140-
141- # IMPROVED: Standardized source name to lowercase
142- packages .append ((name , desc , "dnf" ))
143- logger .debug (f"Found DNF package: { name } " )
156+ logger .info (f"DNF search completed: { len (packages )} packages found from { lines_processed } lines" )
144157
145158 logger .info (f"DNF search completed: { len (packages )} packages found from { lines_processed } lines" )
146159
0 commit comments