Skip to content

Commit e49784d

Browse files
committed
Fixed dependency issues with git repostories
1 parent 648a5dc commit e49784d

File tree

4 files changed

+67
-11
lines changed

4 files changed

+67
-11
lines changed

.gitlab-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ Build:
117117
# Also fetch & checkout DVC-managed data, $CI_DVC_CACHE_DIR persists between jobs
118118
- |
119119
source .venv/bin/activate
120-
finn deps update --dependency-path ./deps
120+
finn deps update --dependency-path ./deps --accept-defaults
121121
dvc config cache.dir $CI_DVC_CACHE_DIR
122122
dvc pull
123123
artifacts:

src/finn/interface/manage_deps.py

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
from __future__ import annotations
44

5+
import importlib.util
56
import os
67
import shlex
78
import shutil
89
import subprocess as sp
910
import sys
11+
import traceback
1012
import yaml
1113
from concurrent.futures import Future, ThreadPoolExecutor
1214
from itertools import chain
@@ -22,7 +24,12 @@
2224

2325
from finn.interface import IS_POSIX
2426
from finn.interface.interface_utils import debug, error, resolve_module_path
25-
from finn.util.exception import FINNConfigurationError, FINNUserError
27+
from finn.util.exception import (
28+
FINNConfigurationError,
29+
FINNDependencyInstallationError,
30+
FINNUserError,
31+
)
32+
2633
from pydantic.networks import HttpUrl # noqa
2734

2835

@@ -302,9 +309,25 @@ def _run_silent(self, cmd: str, cwd: Path | None = None, timeout: float | None =
302309
def _git_clone(self, url: str, commit: str, target: Path) -> bool:
303310
"""Try to clone and checkout the git url to the given target directory. If something
304311
went wrong return False, True otherwise.""" # noqa
305-
if self._run_silent(f"git clone {url} {target.absolute()}", timeout=self.git_timeout) != 0:
312+
clone_result = sp.run(
313+
shlex.split(f"git clone {url} {target.absolute()}"),
314+
timeout=self.git_timeout,
315+
capture_output=True,
316+
text=True,
317+
)
318+
if clone_result.returncode != 0:
319+
debug(f"[{url}] Cloning failed! Output was:\n{clone_result.stderr}", False)
320+
return False
321+
checkout_result = sp.run(
322+
shlex.split(f"git checkout {commit}"),
323+
cwd=target.absolute(),
324+
capture_output=True,
325+
text=True,
326+
)
327+
if checkout_result.returncode != 0:
328+
debug(f"[{url}] Checkout failed! Output was:\n{checkout_result.stderr}", False)
306329
return False
307-
return self._run_silent(f"git checkout {commit}", cwd=target.absolute()) == 0
330+
return True
308331

309332
def _get_git_hash(self, package_name: str) -> str | None:
310333
"""Return the hash of the given package_name dependency.
@@ -334,15 +357,24 @@ def _install_git_dependency(self, package_name: str) -> bool:
334357
package_name, "url", "commit", "pip_install", "install_editable"
335358
)
336359
target = self.dep_location / package_name
360+
if target.exists() and importlib.util.find_spec(package_name.replace("-", "_")) is None:
361+
debug(
362+
"Git repository seems to exist, but is not installed "
363+
"into this environment. Removing dependency and cloning again.",
364+
False,
365+
)
366+
shutil.rmtree(target, ignore_errors=True)
337367
if not self._git_clone(url, commit, target):
368+
debug(f"[{package_name}] Cloning or checkout failed.", False)
338369
return False
339370
if self.is_outdated(package_name):
340371
return False
341372
if not pip_install:
342373
return True
343-
debug(f"[{package_name}] Running pip install..")
344374
editable_flag = "" if not install_editable else "-e"
345-
self._run_silent(f"{sys.executable} -m pip {editable_flag} install {target}")
375+
pip_install_command = f"{sys.executable} -m pip install {editable_flag} {target}"
376+
debug(f"[{package_name}] Running pip install: {pip_install_command}")
377+
self._run_silent(pip_install_command)
346378

347379
# In editable install cases we need to make the package available in this run
348380
# otherwise it will only be available on the next start
@@ -431,6 +463,10 @@ def _install_finn_xsi(self) -> bool:
431463
"""Install FINN XSI bindings and return if installation was successful."""
432464
debug("[finn_xsi] Preparing LD LIBRARY PATH", False)
433465
finn_xsi_path = Path(self.finn_xsi_str)
466+
if "XILINX_VIVADO" not in os.environ:
467+
raise FINNDependencyInstallationError(
468+
"Vivado is not available " "(or XILINX_VIVADO is not set in your " "environment)!"
469+
)
434470
vivado_path = os.environ["XILINX_VIVADO"]
435471
required_paths = f"/lib/x86_64-linux-gnu/:{vivado_path}/lib/lnx64.o"
436472
if "LD_LIBRARY_PATH" not in os.environ:
@@ -518,11 +554,17 @@ def is_outdated(self, package_name: str, installed: bool = False) -> bool:
518554

519555
# If it doesnt exist yet, its definitely outdated
520556
if has_hash is None:
557+
debug(f"[{package_name}] No commit hash found - outdated.", False)
521558
return True
522559

523560
# Compare hashes
524561
data = cast("GitDependency", data)
525562
if data.commit != has_hash:
563+
debug(
564+
f"[{package_name}] No matching hash commits: expected "
565+
f"{data.commit}, got {has_hash}",
566+
False,
567+
)
526568
return True
527569

528570
# In some cases we do not want to check if the dependency is installed
@@ -532,11 +574,10 @@ def is_outdated(self, package_name: str, installed: bool = False) -> bool:
532574
# For pip-installable dependencies, also check if the package is accessible
533575
# in the current Python process
534576
if package_name in self.deps.git_deps and data.pip_install:
535-
import importlib.util
536-
537577
# Try to find the package in the current Python environment
538578
spec = importlib.util.find_spec(package_name.replace("-", "_"))
539579
if spec is None:
580+
debug(f"[{package_name}] is not importable!", False)
540581
# Package is not importable, mark as outdated
541582
return True
542583

@@ -570,8 +611,15 @@ def install_wrapper(package_name: str, status: _StatusTracker) -> bool:
570611
result = self.install_dependency(package_name)
571612
status.set_finish(package_name, result)
572613
return result
573-
except Exception:
614+
except FINNDependencyInstallationError as e:
615+
status.set_finish(package_name, False)
616+
status.update_status(package_name, f"Error: {e}", "purple")
617+
status.update_live()
618+
return False
619+
except Exception as e:
574620
status.set_finish(package_name, False)
621+
debug(f"[{package_name}] Exception: {e}", False)
622+
debug(f"[{package_name}] {traceback.format_exc()}", False)
575623
status.update_status(
576624
package_name, "Updated failed! (Internal exception!)", "purple"
577625
)

src/finn/interface/settings.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from __future__ import annotations
55

66
import json
7+
import multiprocessing
78
import os
8-
import psutil
99
import yaml
1010
from importlib.metadata import distribution
1111
from pathlib import Path
@@ -101,7 +101,7 @@ def num_default_workers(self) -> int:
101101
"""Number of default parallel workers."""
102102
if self._num_default_workers > -1:
103103
return self._num_default_workers
104-
cpus = psutil.cpu_count()
104+
cpus = multiprocessing.cpu_count()
105105
if cpus is None or cpus == 1:
106106
return 1
107107
return int(cpus * 0.75)

src/finn/util/exception.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ def __init__(self, *args: object) -> None:
3636
super().__init__(*args)
3737

3838

39+
class FINNDependencyInstallationError(FINNUserError):
40+
"""Error emitted by the DependencyManager if something fails."""
41+
42+
def __init__(self, *args: object) -> None:
43+
"""Create a new FINNValidationError."""
44+
super().__init__(*args)
45+
46+
3947
class FINNValidationError(FINNUserError):
4048
"""Error emitted if the settings could not be properly parsed by Pydantic."""
4149

0 commit comments

Comments
 (0)