Skip to content

Commit 301778e

Browse files
committed
Optimize package search
1 parent 2350a67 commit 301778e

File tree

1 file changed

+78
-31
lines changed

1 file changed

+78
-31
lines changed

usr/lib/linuxmint/mintinstall/mintinstall.py

Lines changed: 78 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from pathlib import Path
2020
import traceback
2121
from operator import attrgetter
22+
from collections import namedtuple
2223

2324
import gi
2425
gi.require_version('Gtk', '3.0')
@@ -611,6 +612,8 @@ def __init__(self, category):
611612

612613
self.add(box)
613614

615+
PkgInfoSearchCache = namedtuple('PkgInfoSearchCache', ['name', 'display_name', 'keywords', 'summary', 'description'])
616+
614617
class Application(Gtk.Application):
615618
(ACTION_TAB, PROGRESS_TAB, SPINNER_TAB) = list(range(3))
616619

@@ -1072,6 +1075,8 @@ def on_installer_ready(self):
10721075
# Can take some time, don't block for it (these are categorizing packages based on apt info, not our listings)
10731076
GLib.idle_add(self.process_unmatched_packages)
10741077

1078+
GLib.idle_add(self.pregenerate_search_cache)
1079+
10751080
housekeeping.run()
10761081

10771082
self.refresh_cache_menuitem.set_sensitive(True)
@@ -1397,11 +1402,11 @@ def on_process_exited(proc, result):
13971402
# Add a callback when we exit mintsources
13981403
p.wait_async(None, on_process_exited)
13991404

1400-
def should_show_pkginfo(self, pkginfo):
1405+
def should_show_pkginfo(self, pkginfo, allow_unverified_flatpaks):
14011406
if pkginfo.pkg_hash.startswith("apt"):
14021407
return True
14031408

1404-
if not self.settings.get_boolean(prefs.ALLOW_UNVERIFIED_FLATPAKS):
1409+
if not allow_unverified_flatpaks:
14051410
return pkginfo.verified
14061411

14071412
return pkginfo.refid.startswith("app/")
@@ -1753,6 +1758,10 @@ def on_search_changed(self, searchentry):
17531758
self.show_category(self.current_category)
17541759
elif terms != "" and len(terms) >= 3:
17551760
self.show_search_results(terms)
1761+
elif terms == "":
1762+
page = self.page_stack.get_visible_child_name()
1763+
if page == self.PAGE_LIST or page == self.PAGE_SEARCHING:
1764+
self.go_back_action()
17561765

17571766
self.search_changed_timer = 0
17581767
return False
@@ -2185,6 +2194,11 @@ def show_active_tasks(self):
21852194
def on_back_button_clicked(self, button):
21862195
self.go_back_action()
21872196

2197+
def cancel_running_search(self):
2198+
if self.search_idle_timer > 0:
2199+
GLib.source_remove(self.search_idle_timer)
2200+
self.search_idle_timer = 0
2201+
21882202
def go_back_action(self):
21892203
XApp.set_window_progress(self.main_window, 0)
21902204
self.stop_progress_pulse()
@@ -2202,6 +2216,8 @@ def go_back_action(self):
22022216
self.installer.cancel_task(self.current_task)
22032217
self.current_task = None
22042218

2219+
self.cancel_running_search()
2220+
22052221
if self.page_stack.get_visible_child_name() == self.PAGE_PREFS:
22062222
self.search_tool_item.set_sensitive(True)
22072223

@@ -2299,6 +2315,37 @@ def get_application_icon(self, pkginfo, size):
22992315

23002316
return imaging.get_icon(icon_string, size)
23012317

2318+
def update_package_search_cache(self, pkginfo, search_in_description):
2319+
if not hasattr(pkginfo, "search_cache"):
2320+
pkginfo.search_cache = PkgInfoSearchCache(
2321+
name=pkginfo.name.upper(),
2322+
display_name=pkginfo.get_display_name().upper(),
2323+
keywords=pkginfo.get_keywords().upper(),
2324+
summary=pkginfo.get_summary().upper(),
2325+
description=None
2326+
if not search_in_description
2327+
else self.installer.get_description(pkginfo, for_search=True).upper()
2328+
)
2329+
2330+
# installer.get_description() is very slow, so we only fetch it if it's required
2331+
if search_in_description and pkginfo.search_cache.description is None:
2332+
description = self.installer.get_description(pkginfo, True).upper()
2333+
pkginfo.search_cache = pkginfo.search_cache._replace(description=description)
2334+
2335+
def pregenerate_search_cache(self):
2336+
search_in_description = self.settings.get_boolean(prefs.SEARCH_IN_DESCRIPTION)
2337+
pkginfos = self.installer.cache.values()
2338+
2339+
def generate_package_cache(pkginfos):
2340+
try:
2341+
pkginfo = next(pkginfos)
2342+
self.update_package_search_cache(pkginfo, search_in_description)
2343+
return True
2344+
except StopIteration:
2345+
return False
2346+
2347+
GLib.idle_add(generate_package_cache, iter(pkginfos))
2348+
23022349
@print_timing
23032350
def show_search_results(self, terms):
23042351
if not self.gui_ready:
@@ -2333,53 +2380,65 @@ def show_search_results(self, terms):
23332380

23342381
searched_packages = []
23352382

2336-
if self.search_idle_timer > 0:
2337-
GLib.source_remove(self.search_idle_timer)
2338-
self.search_idle_timer = 0
2383+
self.cancel_running_search()
23392384

23402385
search_in_summary = self.settings.get_boolean(prefs.SEARCH_IN_SUMMARY)
23412386
search_in_description = self.settings.get_boolean(prefs.SEARCH_IN_DESCRIPTION)
23422387

23432388
package_type_preference = self.settings.get_string(prefs.PACKAGE_TYPE_PREFERENCE)
23442389
hidden_packages = set()
2390+
allow_unverified_flatpaks = self.settings.get_boolean(prefs.ALLOW_UNVERIFIED_FLATPAKS)
23452391

23462392
def idle_search_one_package(pkginfos):
23472393
try:
2348-
pkginfo = pkginfos.pop(0)
2349-
except IndexError:
2394+
pkginfo = next(pkginfos)
2395+
except StopIteration:
23502396
self.search_idle_timer = 0
2397+
2398+
if package_type_preference == prefs.PACKAGE_TYPE_PREFERENCE_APT:
2399+
results = [p for p in searched_packages if not (p.pkg_hash.startswith("f") and p.name in hidden_packages)]
2400+
elif package_type_preference == prefs.PACKAGE_TYPE_PREFERENCE_FLATPAK:
2401+
results = [p for p in searched_packages if not (p.pkg_hash.startswith("a") and p.name in hidden_packages)]
2402+
else:
2403+
results = searched_packages
2404+
2405+
GLib.idle_add(self.on_search_results_complete, results)
23512406
return False
23522407

23532408
flatpak = pkginfo.pkg_hash.startswith("f")
23542409
is_match = False
23552410

23562411
while True:
2357-
if not self.should_show_pkginfo(pkginfo):
2412+
if not self.should_show_pkginfo(pkginfo, allow_unverified_flatpaks):
23582413
break
23592414

2360-
if all(piece in pkginfo.name.upper() for piece in termsSplit):
2415+
self.update_package_search_cache(pkginfo, search_in_description)
2416+
2417+
if all(piece in pkginfo.search_cache.name for piece in termsSplit):
23612418
is_match = True
23622419
pkginfo.search_tier = 0
23632420
break
2421+
23642422
# pkginfo.name for flatpaks is their id (org.foo.BarMaker), which
23652423
# may not actually contain the app's name. In this case their display
23662424
# names are better. The 'name' is still checked first above, because
23672425
# it's static - get_display_name() may involve a lookup with appstream.
2368-
if flatpak and all(piece in pkginfo.get_display_name().upper() for piece in termsSplit):
2426+
if flatpak and all(piece in pkginfo.search_cache.display_name for piece in termsSplit):
23692427
is_match = True
23702428
pkginfo.search_tier = 0
23712429
break
23722430

2373-
if termsUpper in pkginfo.get_keywords().upper():
2431+
if termsUpper in pkginfo.search_cache.keywords:
23742432
is_match = True
23752433
pkginfo.search_tier = 50
23762434
break
23772435

2378-
if (search_in_summary and termsUpper in pkginfo.get_summary().upper()):
2436+
if (search_in_summary and termsUpper in pkginfo.search_cache.summary):
23792437
is_match = True
23802438
pkginfo.search_tier = 100
23812439
break
2382-
if(search_in_description and termsUpper in self.installer.get_description(pkginfo).upper()):
2440+
2441+
if (search_in_description and termsUpper in pkginfo.search_cache.description):
23832442
is_match = True
23842443
pkginfo.search_tier = 200
23852444
break
@@ -2392,23 +2451,9 @@ def idle_search_one_package(pkginfos):
23922451
elif package_type_preference == prefs.PACKAGE_TYPE_PREFERENCE_FLATPAK and flatpak:
23932452
hidden_packages.add(DEB_EQUIVS.get(pkginfo.name))
23942453

2395-
# Repeat until empty
2396-
if len(pkginfos) > 0:
2397-
return True
2398-
2399-
self.search_idle_timer = 0
2400-
2401-
if package_type_preference == prefs.PACKAGE_TYPE_PREFERENCE_APT:
2402-
results = [p for p in searched_packages if not (p.pkg_hash.startswith("f") and p.name in hidden_packages)]
2403-
elif package_type_preference == prefs.PACKAGE_TYPE_PREFERENCE_FLATPAK:
2404-
results = [p for p in searched_packages if not (p.pkg_hash.startswith("a") and p.name in hidden_packages)]
2405-
else:
2406-
results = searched_packages
2407-
2408-
GLib.idle_add(self.on_search_results_complete, results)
2409-
return False
2454+
return True
24102455

2411-
self.search_idle_timer = GLib.idle_add(idle_search_one_package, list(listing))
2456+
self.search_idle_timer = GLib.idle_add(idle_search_one_package, iter(listing))
24122457

24132458
def on_search_results_complete(self, results):
24142459
self.page_stack.set_visible_child_name(self.PAGE_LIST)
@@ -2479,6 +2524,7 @@ def sort_packages(self, pkgs, key_func):
24792524

24802525
def show_packages(self, pkginfos, from_search=False):
24812526
self.stop_slideshow_timer()
2527+
allow_unverified_flatpaks = self.settings.get_boolean(prefs.ALLOW_UNVERIFIED_FLATPAKS)
24822528

24832529
if self.one_package_idle_timer > 0:
24842530
GLib.source_remove(self.one_package_idle_timer)
@@ -2515,7 +2561,7 @@ def show_packages(self, pkginfos, from_search=False):
25152561
apps = [info for info in pkginfos] # should_show_pkginfo was applied during search matching
25162562
apps = self.sort_packages(apps, attrgetter("unverified", "search_tier", "score_desc", "name"))
25172563
else:
2518-
apps = [info for info in pkginfos if self.should_show_pkginfo(info)]
2564+
apps = [info for info in pkginfos if self.should_show_pkginfo(info, allow_unverified_flatpaks)]
25192565
apps = self.sort_packages(apps, attrgetter("unverified", "score_desc", "name"))
25202566
apps = apps[0:201]
25212567

@@ -2845,10 +2891,11 @@ def on_package_type_button_clicked(self, button, pkginfo):
28452891
self.show_package(pkginfo, self.previous_page)
28462892

28472893
def get_flatpak_for_deb(self, pkginfo):
2894+
allow_unverified_flatpaks = self.settings.get_boolean(prefs.ALLOW_UNVERIFIED_FLATPAKS)
28482895
try:
28492896
fp_name = FLATPAK_EQUIVS[pkginfo.name]
28502897
flatpak_pkginfo = self.installer.find_pkginfo(fp_name, installer.PKG_TYPE_FLATPAK)
2851-
if self.should_show_pkginfo(flatpak_pkginfo):
2898+
if self.should_show_pkginfo(flatpak_pkginfo, allow_unverified_flatpaks):
28522899
return flatpak_pkginfo
28532900
except:
28542901
return None

0 commit comments

Comments
 (0)