Skip to content

Commit

Permalink
Rework remove pkgs dialog and update some testcases
Browse files Browse the repository at this point in the history
  • Loading branch information
goszpeti committed Aug 27, 2024
1 parent 9306b35 commit 4cabeac
Show file tree
Hide file tree
Showing 12 changed files with 343 additions and 153 deletions.
137 changes: 67 additions & 70 deletions src/conan_explorer/conan_wrapper/conan_cleanup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,27 @@
import platform
from typing import TYPE_CHECKING, Dict, List, Set

import conan_explorer.app as app
from conan_explorer import conan_version
from conan_explorer.app.logger import Logger
from conan_explorer.app.system import get_folder_size_mb
from conan_explorer.conan_wrapper.types import ConanRef
if TYPE_CHECKING:
from .conanV1 import ConanApi

class ConanCleanup():

def __init__(self, conan_api: "ConanApi") -> None:
self._conan_api = conan_api
def __init__(self) -> None:
self.cleanup_refs_info: Dict[str, Dict[str, str]] = {}
self.invalid_metadata_refs: Set[str] = set()

def gather_invalid_remote_metadata(self) -> List[str]:
""" Gather all references with invalid remotes """
invalid_refs = []
remotes = self._conan_api.get_remotes(include_disabled=True)
remotes = app.conan_api.get_remotes(include_disabled=True)
remote_names = [r.name for r in remotes]
for ref in self._conan_api.get_all_local_refs():
for ref in app.conan_api.get_all_local_refs():
# This will not updated to the unified API - only V1 relevant
ref_cache = self._conan_api._client_cache.package_layout(ref)
ref_cache = app.conan_api._client_cache.package_layout(ref)
ref_remote = ""
try:
ref_remote = ref_cache.load_metadata().recipe.remote # type: ignore
Expand All @@ -38,26 +37,29 @@ def gather_invalid_remote_metadata(self) -> List[str]:
def repair_invalid_remote_metadata(self, invalid_ref):
""" Repair all references with invalid remotes """
# calling inspect with a correct remote repiars the metadata
for remote in self._conan_api.get_remotes():
for remote in app.conan_api.get_remotes():
try:
self._conan_api._conan.inspect(invalid_ref, None, remote.name)
app.conan_api._conan.inspect(invalid_ref, None, remote.name)
break
except Exception:
continue

def get_cleanup_cache_info(self) -> Dict[str, Dict[str, str]]:
""" Get a list of orphaned short path and cache folders """
if platform.system() != "Windows" or conan_version.major == 2:
return {} # TODO: Fix for linux
from .types import PackageEditableLayout, CONAN_LINK
del_list = {}
for ref in self._conan_api.get_all_local_refs():
# This will not updated to the unified API - only V1 relevant
ref_cache = self._conan_api._client_cache.package_layout(ref)
ref_str = str(ref)
return {} # TODO: Update for linux
from .types import CONAN_LINK
editables = app.conan_api.get_editable_references()

for conan_ref in app.conan_api.get_all_local_refs():
if conan_ref in editables:
continue
current_ref_info = {}

# Get orphaned refs
# this will not updated to the unified API - only V1 relevant
ref_cache = app.conan_api._client_cache.package_layout(conan_ref) # type: ignore

# get orphaned refs
package_ids = []
try:
package_ids = ref_cache.package_ids()
Expand All @@ -66,47 +68,40 @@ def get_cleanup_cache_info(self) -> Dict[str, Dict[str, str]]:
# old API of Conan
package_ids = ref_cache.packages_ids() # type: ignore
except Exception as e:
Logger().debug("Cannot check pkg id for %s: %s", ref, str(e), exc_info=True)
Logger().debug("Cannot check pkg id for %s: %s", str(conan_ref), str(e), exc_info=True)

for pkg_id in package_ids:
short_path_dir = self._conan_api.get_package_folder(ref, pkg_id)
pkg_id_dir = None
# This will not updated to the unified API - only V1 relevant
ref_cache = self._conan_api._client_cache.package_layout(ref)
if not isinstance(ref_cache, PackageEditableLayout):
pkg_id_dir = Path(ref_cache.packages()) / pkg_id
short_path_dir = app.conan_api.get_package_folder(conan_ref, pkg_id)
if not short_path_dir.exists():
if pkg_id_dir:
current_ref_info[str(pkg_id)] = str(pkg_id_dir)

current_ref_info[str(pkg_id)] = str(Path(ref_cache.packages()) / pkg_id)

# get temporary dirs
if not isinstance(ref_cache, PackageEditableLayout):
source_path = Path(ref_cache.source())
if source_path.exists():
# check for .conan_link
if (source_path / CONAN_LINK).is_file():
path = (source_path / CONAN_LINK).read_text()
current_ref_info["source"] = path.strip()
else:
current_ref_info["source"] = ref_cache.source()
source_path = Path(ref_cache.source())
if source_path.exists():
# check for .conan_link
if (source_path / CONAN_LINK).is_file():
path = (source_path / CONAN_LINK).read_text()
current_ref_info["source"] = path.strip()
else:
current_ref_info["source"] = ref_cache.source()

if Path(ref_cache.builds()).exists():
current_ref_info["build"] = ref_cache.builds()
if Path(ref_cache.builds()).exists():
current_ref_info["build"] = ref_cache.builds()

scm_source_path = Path(ref_cache.scm_sources())
if scm_source_path.exists():
# check for .conan_link
if (scm_source_path / CONAN_LINK).is_file():
path = (scm_source_path / CONAN_LINK).read_text()
current_ref_info["scm_source"] = path.strip()
else:
current_ref_info["scm_source"] = ref_cache.scm_sources()
download_folder = Path(ref_cache.base_folder()) / "dl"
if download_folder.exists():
current_ref_info["download"] = str(download_folder)
if current_ref_info:
del_list[ref_str] = current_ref_info
self.cleanup_refs_info.update(del_list)
scm_source_path = Path(ref_cache.scm_sources())
if scm_source_path.exists():
# check for .conan_link
if (scm_source_path / CONAN_LINK).is_file():
path = (scm_source_path / CONAN_LINK).read_text()
current_ref_info["scm_source"] = path.strip()
else:
current_ref_info["scm_source"] = ref_cache.scm_sources()
download_folder = Path(ref_cache.base_folder()) / "dl"
if download_folder.exists():
current_ref_info["download"] = str(download_folder)

if current_ref_info:
self.cleanup_refs_info[str(conan_ref)] = current_ref_info

self.find_orphaned_packages()
self.cleanup_refs_info = dict(sorted(self.cleanup_refs_info.items()))
Expand All @@ -118,25 +113,27 @@ def find_orphaned_packages(self):
return {}
from .types import CONAN_REAL_PATH

del_list = {}
short_path_folders = [f for f in self._conan_api.get_short_path_root().iterdir()
short_path_folders = [f for f in app.conan_api.get_short_path_root().iterdir()
if f.is_dir()]
for short_path in short_path_folders:
rp_file = short_path / CONAN_REAL_PATH
if rp_file.is_file():
real_path = rp_file.read_text()
if not Path(real_path).is_dir():
conan_ref = "Unknown"
type = "Unknown"
try:
# try to reconstruct conan ref from real_path
rel_path = Path(real_path).relative_to(self._conan_api.get_storage_path())
type = rel_path.parts[4]
conan_ref = str(ConanRef(rel_path.parts[0],
rel_path.parts[1], rel_path.parts[2], rel_path.parts[3]))

except Exception:
Logger().error(f"Can't read {CONAN_REAL_PATH} in {str(short_path)}")
if not self.cleanup_refs_info.get(conan_ref):
self.cleanup_refs_info[conan_ref] = {}
self.cleanup_refs_info[conan_ref][type] = str(short_path)
if not rp_file.is_file():
continue
real_path = rp_file.read_text()

if Path(real_path).is_dir():
continue
conan_ref = "Unknown"
type = "Unknown"
try:
# try to reconstruct conan ref from real_path
rel_path = Path(real_path).relative_to(app.conan_api.get_storage_path())
type = rel_path.parts[4]
conan_ref = str(ConanRef(rel_path.parts[0],
rel_path.parts[1], rel_path.parts[2], rel_path.parts[3]))

except Exception:
Logger().error(f"Can't read {CONAN_REAL_PATH} in {str(short_path)}")
if not self.cleanup_refs_info.get(conan_ref):
self.cleanup_refs_info[conan_ref] = {}
self.cleanup_refs_info[conan_ref][type] = str(short_path)
2 changes: 1 addition & 1 deletion src/conan_explorer/ui/dialogs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .crash import show_bug_reporting_dialog
from .conan_install import ConanInstallDialog
from .conan_remove import ConanRemoveDialog
from .conan_remove.conan_remove import ConanRemoveDialog
from .reorder_dialog import ReorderController, ReorderDialog, ReorderingModel
from .file_editor_selection import FileEditorSelDialog
57 changes: 0 additions & 57 deletions src/conan_explorer/ui/dialogs/conan_remove.py

This file was deleted.

1 change: 1 addition & 0 deletions src/conan_explorer/ui/dialogs/conan_remove/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .conan_remove import ConanRemoveDialog
65 changes: 65 additions & 0 deletions src/conan_explorer/ui/dialogs/conan_remove/conan_remove.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from typing import Dict, List, Optional

import conan_explorer.app as app
from conan_explorer.app import LoaderGui # using global module pattern
from conan_explorer.app.logger import Logger

from PySide6.QtCore import SignalInstance, Qt
from PySide6.QtWidgets import QDialog, QWidget, QDialogButtonBox, QListWidgetItem

from conan_explorer.conan_wrapper.types import ConanRef


class ConanRemoveDialog(QDialog):

def __init__(self, parent: Optional[QWidget], conan_refs_with_pkg_ids: Dict[str, List[str]],
conan_pkg_removed: Optional[SignalInstance] = None):
super().__init__(parent)
self._conan_pkg_removed_sig = conan_pkg_removed
from .conan_remove_ui import Ui_Dialog
self._ui = Ui_Dialog()
self._ui.setupUi(self)

for conan_ref, pkg_ids in conan_refs_with_pkg_ids.items():
for pkg_id in pkg_ids:
if not pkg_id:
text = conan_ref
else:
text = f"{conan_ref}:{pkg_id}"
list_item = QListWidgetItem(text)
list_item.setCheckState(Qt.CheckState.Checked)
self._ui.package_list_widget.addItem(list_item)

self._ui.button_box.button(
QDialogButtonBox.StandardButton.Yes).clicked.connect(self.on_remove)

def on_remove(self):
""" Remove conan ref/pkg and emit a signal, if registered """
self.loader = LoaderGui(self)
self.loader.load_for_blocking(self, self.remove, cancel_button=False, loading_text="Removing packages")
self.loader.wait_for_finished()

def remove(self):
""" Remove the selected ref or pkg. Emit conan_pkg_removed global signal.
To be called while loading dialog is active. """
for list_row in range(self._ui.package_list_widget.count()):
list_item = self._ui.package_list_widget.item(list_row)
if list_item.checkState() != Qt.CheckState.Checked:
continue
conan_ref_with_id = list_item.text()
pkg_id = ""
if ":" in conan_ref_with_id:
conan_ref, pkg_id = conan_ref_with_id.split(":")
else:
conan_ref = conan_ref_with_id
try:
self.loader.loading_string_signal.emit(f"Removing {conan_ref} {pkg_id}")
# can handle multiple pkgs at once, but then we can't log info for the
# progress bar
app.conan_api.remove_reference(ConanRef.loads(conan_ref), pkg_id)
except Exception as e:
Logger().error(f"Error while removing package {conan_ref}: {str(e)}")
continue
if self._conan_pkg_removed_sig:
self._conan_pkg_removed_sig.emit(conan_ref, pkg_id)
Logger().info(f"Removing package {conan_ref_with_id} finished")
Loading

0 comments on commit 4cabeac

Please sign in to comment.