From e46c987c50dc353efffdc0e324a39cdb5a6b0661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20H=C3=A9risson?= Date: Tue, 9 Dec 2025 13:58:24 +0100 Subject: [PATCH 1/5] chore(knime.py): download only for the running platform --- retropath2_wrapper/knime.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/retropath2_wrapper/knime.py b/retropath2_wrapper/knime.py index 06e442b..f3dd67e 100644 --- a/retropath2_wrapper/knime.py +++ b/retropath2_wrapper/knime.py @@ -171,12 +171,20 @@ def download_from_zenodo(cls, path: str, kver: str, logger: Logger = getLogger(_ 4.6.4 or 4.7.0 """ data = Knime.zenodo_show_repo(kver=kver) + if sys.platform == "win32" or sys.platform == "linux": + platform_tag = sys.platform + elif sys.platform == "darwin": + platform_tag = "macosx" + else: + raise RuntimeError(f"Platform {sys.platform} not supported for KNIME installation") for file in data["files"]: basename = file["key"] - url = file["links"]["self"] - foutput = os.path.join(path, basename) - logger.info(f"Download: {url} to {foutput}") - download(url, foutput) + if platform_tag in basename: + url = file["links"]["self"] + foutput = os.path.join(path, basename) + logger.info(f"Download: {url} to {foutput}") + download(url, foutput) + break def install(self, path: str, logger: Logger = getLogger(__name__)) -> bool: """ From 87e4152cd30095298a2b3865f0e87a8dcf57448a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20H=C3=A9risson?= Date: Wed, 10 Dec 2025 01:15:59 +0100 Subject: [PATCH 2/5] fix(knime.py): add missing repos --- retropath2_wrapper/knime.py | 114 +++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 42 deletions(-) diff --git a/retropath2_wrapper/knime.py b/retropath2_wrapper/knime.py index f3dd67e..99fc53d 100644 --- a/retropath2_wrapper/knime.py +++ b/retropath2_wrapper/knime.py @@ -188,82 +188,112 @@ def download_from_zenodo(cls, path: str, kver: str, logger: Logger = getLogger(_ def install(self, path: str, logger: Logger = getLogger(__name__)) -> bool: """ - Install Knime - - Parameters - ---------- - path: str - Directory with all files from Zenodo, such as: - - knime_4.6.4.app.macosx.cocoa.x86_64.dmg - - knime_4.6.4.linux.gtk.x86_64.tar.gz - - knime_4.6.4.win32.win32.x86_64.zip - - org.knime.update.analytics-platform_4.6.4.zip - - TrustedCommunityContributions_4.6_202212212136.zip + Install KNIME and required plugins (headless mode). """ + knime_files = glob.glob(os.path.join(path, "*")) - # Install Knime + + # --------------------------------------------------------- + # 1) Extract KNIME base installation + # --------------------------------------------------------- dirs_before = Knime.collect_top_level_dirs(path=self.kinstall) for file in knime_files: basename = os.path.basename(file) + + # Linux if "linux" in basename and sys.platform == "linux": extract_tar_gz(file, self.kinstall) chown_r(self.kinstall, getuser()) - # chown_r(kinstall, geteuid(), getegid()) break + + # macOS elif "macosx" in basename and sys.platform == "darwin": match = re.search(r"\d+\.\d+\.\d+", basename) - if match: - kver = match.group() - else: - raise ValueError(f"Version can not be guessed from filename: {file}") - app_path = f'{self.kinstall}/KNIME_{kver}.app' + if not match: + raise ValueError(f"Could not determine version from filename: {file}") + kver = match.group() + + app_path = f"{self.kinstall}/KNIME_{kver}.app" if os.path.exists(app_path): shutil.rmtree(app_path) + with tempfile.TemporaryDirectory() as tempd: - cmd = f'hdiutil mount -noverify {file} -mountpoint {tempd}/KNIME' - subprocess_call(cmd, logger=logger) + subprocess_call( + f'hdiutil mount -noverify {file} -mountpoint {tempd}/KNIME', + logger=logger + ) shutil.copytree( - f'{tempd}/KNIME/KNIME {kver}.app', + f"{tempd}/KNIME/KNIME {kver}.app", app_path ) - cmd = f'hdiutil unmount {tempd}/KNIME' - subprocess_call(cmd, logger=logger) + subprocess_call( + f'hdiutil unmount {tempd}/KNIME', + logger=logger + ) break + + # Windows elif "win32" in basename and sys.platform == "win32": unzip(file, self.kinstall) break + dirs_after = Knime.collect_top_level_dirs(path=self.kinstall) dirs_only_after = dirs_after - dirs_before - assert len(dirs_only_after) == 1, dirs_only_after + assert len(dirs_only_after) == 1, f"New directory not unique: {dirs_only_after}" + + knime_root = os.path.abspath(os.path.join(self.kinstall, dirs_only_after.pop())) - # Download Plugins - path_plugins = [] + # --------------------------------------------------------- + # 2) Collect local plugin repositories (ZIPs from Zenodo) + # --------------------------------------------------------- + local_repos = [] for file in knime_files: basename = os.path.basename(file) - if "org.knime.update" in basename or "TrustedCommunity" in basename: - path_plugins.append(os.path.abspath(file)) - - # Install Plugins + if ("org.knime.update" in basename or + "TrustedCommunity" in basename or + "chemistry" in basename.lower()): # allow offline chemistry repo ZIP too + local_repos.append(f"jar:file:{os.path.abspath(file)}!/") + + # --------------------------------------------------------- + # 3) Add online repositories (required for chemistry & RDKit) + # --------------------------------------------------------- + online_repos = [ + "https://update.knime.com/analytics-platform/4.6/", + "https://update.knime.com/analytics-platform/4.6/chemistry/", + # optional but useful: + "https://update.knime.com/community-contributions/trusted/4.6/" + ] + + all_repos = local_repos + online_repos + + # --------------------------------------------------------- + # 4) Run p2 director to install plugins + # --------------------------------------------------------- self.kexec = Knime.find_executable(path=self.kinstall) p2_dir = Knime.find_p2_dir(path=self.kinstall) - - if not self.kexec or not os.path.exists(self.kexec): + + if not self.kexec: raise FileNotFoundError(f"KNIME executable not found under {self.kinstall}") if not p2_dir: raise RuntimeError("p2 directory not found after installation.") - - args = [f"{self.kexec}"] - args += ["-nosplash", "-consoleLog"] - args += ["-application", "org.eclipse.equinox.p2.director"] - args += ["-repository", ",".join([f"jar:file:{path_plugin}!/" for path_plugin in path_plugins])] - args += ["-bundlepool", p2_dir] - args += ["-destination", os.path.abspath(os.path.join(self.kinstall, dirs_only_after.pop()))] - args += ["-i", ",".join(Knime.PLUGINS)] - logger.info("Command line to install Knime plugins") + + args = [ + self.kexec, + "-nosplash", + "-consoleLog", + "-application", "org.eclipse.equinox.p2.director", + "-repository", ",".join(all_repos), + "-bundlepool", p2_dir, + "-destination", knime_root, + "-i", ",".join(Knime.PLUGINS) + ] + + logger.info("Command line to install KNIME plugins:") logger.info(" ".join(args)) + CPE = subprocess.run(args) logger.debug(CPE) - + return True def call( From b8fbfece1f380744b06ae803b8a3642f1771adbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20H=C3=A9risson?= Date: Wed, 10 Dec 2025 01:18:43 +0100 Subject: [PATCH 3/5] chore(knime.py): rm 'unzip' patch (fixed) --- retropath2_wrapper/knime.py | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/retropath2_wrapper/knime.py b/retropath2_wrapper/knime.py index 99fc53d..9c2db44 100644 --- a/retropath2_wrapper/knime.py +++ b/retropath2_wrapper/knime.py @@ -34,23 +34,6 @@ from retropath2_wrapper.preference import Preference -# Patch for brs-utils: https://github.com/brsynth/brs-utils/issues/6 -def unzip( - file: str, - dir: str -) -> None: - '''Unzip the given file. - - Parameters - ---------- - file: str - Filename to unzip - dir: str - Directory to unzip into - ''' - with ZipFile(file, 'r') as zip_ref: - zip_ref.extractall(dir) - class Knime(object): """Knime is useful to install executable, install packages or commandline. http://download.knime.org/analytics-platform/ @@ -218,18 +201,14 @@ def install(self, path: str, logger: Logger = getLogger(__name__)) -> bool: shutil.rmtree(app_path) with tempfile.TemporaryDirectory() as tempd: - subprocess_call( - f'hdiutil mount -noverify {file} -mountpoint {tempd}/KNIME', - logger=logger - ) + cmd = f'hdiutil mount -noverify {file} -mountpoint {tempd}/KNIME' + subprocess_call(cmd, logger=logger) shutil.copytree( - f"{tempd}/KNIME/KNIME {kver}.app", + f'{tempd}/KNIME/KNIME {kver}.app', app_path ) - subprocess_call( - f'hdiutil unmount {tempd}/KNIME', - logger=logger - ) + cmd = f'hdiutil unmount {tempd}/KNIME' + subprocess_call(cmd, logger=logger) break # Windows From 922fce24d39389e1e7bfe07068e1d74a40d82dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20H=C3=A9risson?= Date: Wed, 10 Dec 2025 01:26:12 +0100 Subject: [PATCH 4/5] build(environment.yaml): update brs-utils min version --- environment-macos_arm64.yaml | 2 +- environment.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/environment-macos_arm64.yaml b/environment-macos_arm64.yaml index 1159759..3602467 100644 --- a/environment-macos_arm64.yaml +++ b/environment-macos_arm64.yaml @@ -3,7 +3,7 @@ channels: - conda-forge dependencies: - python >=3.10 - - brs_utils >=1.23.1 + - brs_utils >=1.24.2 - filetype - colored - freetype \ No newline at end of file diff --git a/environment.yaml b/environment.yaml index a92fc69..4717d1f 100644 --- a/environment.yaml +++ b/environment.yaml @@ -2,7 +2,7 @@ name: retropath2_wrapper channels: - conda-forge dependencies: - - brs_utils >=1.23.1 + - brs_utils >=1.24.2 - filetype - colored - freetype From 5343e255148090a1ea7ad19ac9101829c26e7a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20H=C3=A9risson?= Date: Wed, 10 Dec 2025 01:38:13 +0100 Subject: [PATCH 5/5] fix(knime.py): import unzip --- retropath2_wrapper/knime.py | 1 + 1 file changed, 1 insertion(+) diff --git a/retropath2_wrapper/knime.py b/retropath2_wrapper/knime.py index 9c2db44..fe68a8f 100644 --- a/retropath2_wrapper/knime.py +++ b/retropath2_wrapper/knime.py @@ -26,6 +26,7 @@ download, chown_r, subprocess_call, + unzip ) from retropath2_wrapper.Args import ( DEFAULTS,