simfix 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- simfix/__init__.py +3 -0
- simfix/analyzer.py +121 -0
- simfix/cli.py +433 -0
- simfix/cmake.py +61 -0
- simfix/commands.py +91 -0
- simfix/compatibility.py +97 -0
- simfix/conda_environment.py +58 -0
- simfix/conda_fixer.py +145 -0
- simfix/cuda_docker.py +163 -0
- simfix/docker_runner.py +71 -0
- simfix/dockerfile.py +122 -0
- simfix/fixer.py +342 -0
- simfix/git_assets.py +109 -0
- simfix/planner.py +93 -0
- simfix/pypi.py +83 -0
- simfix/pyproject.py +103 -0
- simfix/python_requirements.py +42 -0
- simfix/repo.py +46 -0
- simfix/report.py +191 -0
- simfix/ros_docker.py +110 -0
- simfix/ros_package.py +94 -0
- simfix/setup_py.py +45 -0
- simfix/system.py +154 -0
- simfix/system_docker.py +175 -0
- simfix-0.1.0.dist-info/METADATA +286 -0
- simfix-0.1.0.dist-info/RECORD +30 -0
- simfix-0.1.0.dist-info/WHEEL +5 -0
- simfix-0.1.0.dist-info/entry_points.txt +2 -0
- simfix-0.1.0.dist-info/licenses/LICENSE +21 -0
- simfix-0.1.0.dist-info/top_level.txt +1 -0
simfix/setup_py.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse_setup_py_dependencies(setup_py_path: str | Path) -> list[str]:
|
|
8
|
+
"""Parse simple install_requires dependencies from setup.py."""
|
|
9
|
+
path = Path(setup_py_path).expanduser().resolve()
|
|
10
|
+
|
|
11
|
+
if not path.exists():
|
|
12
|
+
return []
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
tree = ast.parse(path.read_text(encoding="utf-8"))
|
|
16
|
+
except SyntaxError:
|
|
17
|
+
return []
|
|
18
|
+
|
|
19
|
+
dependencies: list[str] = []
|
|
20
|
+
|
|
21
|
+
for node in ast.walk(tree):
|
|
22
|
+
if not isinstance(node, ast.Call):
|
|
23
|
+
continue
|
|
24
|
+
|
|
25
|
+
for keyword in node.keywords:
|
|
26
|
+
if keyword.arg != "install_requires":
|
|
27
|
+
continue
|
|
28
|
+
|
|
29
|
+
dependencies.extend(_parse_dependency_list(keyword.value))
|
|
30
|
+
|
|
31
|
+
return dependencies
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _parse_dependency_list(node: ast.AST) -> list[str]:
|
|
35
|
+
"""Parse dependency list values from an AST node."""
|
|
36
|
+
if not isinstance(node, ast.List | ast.Tuple):
|
|
37
|
+
return []
|
|
38
|
+
|
|
39
|
+
dependencies: list[str] = []
|
|
40
|
+
|
|
41
|
+
for element in node.elts:
|
|
42
|
+
if isinstance(element, ast.Constant) and isinstance(element.value, str):
|
|
43
|
+
dependencies.append(element.value)
|
|
44
|
+
|
|
45
|
+
return dependencies
|
simfix/system.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import platform
|
|
4
|
+
import shutil
|
|
5
|
+
import subprocess
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_linux_os_release() -> tuple[str | None, str | None]:
|
|
11
|
+
"""Return Linux distribution name and version from /etc/os-release."""
|
|
12
|
+
os_release_path = Path("/etc/os-release")
|
|
13
|
+
|
|
14
|
+
if not os_release_path.exists():
|
|
15
|
+
return None, None
|
|
16
|
+
|
|
17
|
+
values: dict[str, str] = {}
|
|
18
|
+
|
|
19
|
+
for line in os_release_path.read_text(encoding="utf-8").splitlines():
|
|
20
|
+
if "=" not in line:
|
|
21
|
+
continue
|
|
22
|
+
|
|
23
|
+
key, value = line.split("=", maxsplit=1)
|
|
24
|
+
values[key] = value.strip().strip('"')
|
|
25
|
+
|
|
26
|
+
distro = values.get("NAME")
|
|
27
|
+
version = values.get("VERSION_ID")
|
|
28
|
+
|
|
29
|
+
return distro, version
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def is_windows_subsystem_for_linux() -> bool:
|
|
33
|
+
"""Return True if running inside Windows Subsystem for Linux."""
|
|
34
|
+
version_path = Path("/proc/version")
|
|
35
|
+
|
|
36
|
+
if not version_path.exists():
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
text = version_path.read_text(encoding="utf-8").lower()
|
|
40
|
+
|
|
41
|
+
return "microsoft" in text or "wsl" in text
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_nvidia_smi_field(field: str) -> str | None:
|
|
45
|
+
"""Return a single field from nvidia-smi query output."""
|
|
46
|
+
if not command_exists("nvidia-smi"):
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
result = subprocess.run(
|
|
50
|
+
[
|
|
51
|
+
"nvidia-smi",
|
|
52
|
+
f"--query-gpu={field}",
|
|
53
|
+
"--format=csv,noheader",
|
|
54
|
+
],
|
|
55
|
+
check=False,
|
|
56
|
+
capture_output=True,
|
|
57
|
+
text=True,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if result.returncode != 0:
|
|
61
|
+
return None
|
|
62
|
+
|
|
63
|
+
first_line = result.stdout.strip().splitlines()[0] if result.stdout.strip() else ""
|
|
64
|
+
|
|
65
|
+
return first_line.strip() or None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_cuda_toolkit_version() -> str | None:
|
|
69
|
+
"""Return CUDA toolkit version from nvcc if available."""
|
|
70
|
+
if not command_exists("nvcc"):
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
result = subprocess.run(
|
|
74
|
+
["nvcc", "--version"],
|
|
75
|
+
check=False,
|
|
76
|
+
capture_output=True,
|
|
77
|
+
text=True,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if result.returncode != 0:
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
for line in result.stdout.splitlines():
|
|
84
|
+
if "release" in line:
|
|
85
|
+
return line.strip()
|
|
86
|
+
|
|
87
|
+
return result.stdout.strip() or None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@dataclass(frozen=True)
|
|
91
|
+
class SystemInfo:
|
|
92
|
+
"""Basic system information relevant for simulator installation."""
|
|
93
|
+
|
|
94
|
+
os_name: str
|
|
95
|
+
os_version: str
|
|
96
|
+
architecture: str
|
|
97
|
+
python_version: str
|
|
98
|
+
linux_distro: str | None
|
|
99
|
+
linux_version: str | None
|
|
100
|
+
is_wsl: bool
|
|
101
|
+
git_available: bool
|
|
102
|
+
docker_available: bool
|
|
103
|
+
nvidia_gpu_available: bool
|
|
104
|
+
nvidia_driver_version: str | None
|
|
105
|
+
nvidia_cuda_version: str | None
|
|
106
|
+
cuda_toolkit_version: str | None
|
|
107
|
+
pip_available: bool
|
|
108
|
+
uv_available: bool
|
|
109
|
+
conda_available: bool
|
|
110
|
+
mamba_available: bool
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def command_exists(command: str) -> bool:
|
|
114
|
+
"""Return True if a command exists on PATH."""
|
|
115
|
+
return shutil.which(command) is not None
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def has_nvidia_gpu() -> bool:
|
|
119
|
+
"""Return True if nvidia-smi is available and runs successfully."""
|
|
120
|
+
if not command_exists("nvidia-smi"):
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
result = subprocess.run(
|
|
124
|
+
["nvidia-smi"],
|
|
125
|
+
check=False,
|
|
126
|
+
capture_output=True,
|
|
127
|
+
text=True,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
return result.returncode == 0
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def get_system_info() -> SystemInfo:
|
|
134
|
+
"""Collect basic system information."""
|
|
135
|
+
linux_distro, linux_version = get_linux_os_release()
|
|
136
|
+
return SystemInfo(
|
|
137
|
+
os_name=platform.system(),
|
|
138
|
+
os_version=platform.release(),
|
|
139
|
+
architecture=platform.machine(),
|
|
140
|
+
python_version=platform.python_version(),
|
|
141
|
+
linux_distro=linux_distro,
|
|
142
|
+
linux_version=linux_version,
|
|
143
|
+
is_wsl=is_windows_subsystem_for_linux(),
|
|
144
|
+
git_available=command_exists("git"),
|
|
145
|
+
docker_available=command_exists("docker"),
|
|
146
|
+
nvidia_gpu_available=has_nvidia_gpu(),
|
|
147
|
+
nvidia_driver_version=get_nvidia_smi_field("driver_version"),
|
|
148
|
+
nvidia_cuda_version=get_nvidia_smi_field("cuda_version"),
|
|
149
|
+
cuda_toolkit_version=get_cuda_toolkit_version(),
|
|
150
|
+
pip_available=command_exists("pip") or command_exists("pip3"),
|
|
151
|
+
uv_available=command_exists("uv"),
|
|
152
|
+
conda_available=command_exists("conda"),
|
|
153
|
+
mamba_available=command_exists("mamba"),
|
|
154
|
+
)
|
simfix/system_docker.py
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
COMMON_SIMULATOR_APT_PACKAGES = [
|
|
7
|
+
"build-essential",
|
|
8
|
+
"cmake",
|
|
9
|
+
"git",
|
|
10
|
+
"pkg-config",
|
|
11
|
+
"python3",
|
|
12
|
+
"python3-pip",
|
|
13
|
+
"libgl1",
|
|
14
|
+
"libglib2.0-0",
|
|
15
|
+
"libx11-6",
|
|
16
|
+
"libxext6",
|
|
17
|
+
"libxrender1",
|
|
18
|
+
"libsm6",
|
|
19
|
+
"libice6",
|
|
20
|
+
"libeigen3-dev",
|
|
21
|
+
"libboost-all-dev",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
SYSTEM_KEYWORDS = {
|
|
26
|
+
"cmake",
|
|
27
|
+
"find_package",
|
|
28
|
+
"opengl",
|
|
29
|
+
"glfw",
|
|
30
|
+
"glew",
|
|
31
|
+
"eigen",
|
|
32
|
+
"boost",
|
|
33
|
+
"sdl",
|
|
34
|
+
"opencv",
|
|
35
|
+
"libgl",
|
|
36
|
+
"build-essential",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True)
|
|
41
|
+
class SystemDockerFixResult:
|
|
42
|
+
"""Result of creating or updating a system dependency Dockerfile."""
|
|
43
|
+
|
|
44
|
+
file_path: Path
|
|
45
|
+
changed: bool
|
|
46
|
+
message: str
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _read_text_if_exists(path: Path) -> str:
|
|
50
|
+
"""Read text from a file if it exists."""
|
|
51
|
+
if not path.exists():
|
|
52
|
+
return ""
|
|
53
|
+
|
|
54
|
+
return path.read_text(encoding="utf-8", errors="ignore")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def detect_system_dependency_project(repo_path: str | Path) -> bool:
|
|
58
|
+
"""Detect whether a repository likely needs Linux system packages."""
|
|
59
|
+
path = Path(repo_path).expanduser().resolve()
|
|
60
|
+
|
|
61
|
+
searchable_text = "\n".join(
|
|
62
|
+
[
|
|
63
|
+
_read_text_if_exists(path / "CMakeLists.txt"),
|
|
64
|
+
_read_text_if_exists(path / "README.md"),
|
|
65
|
+
_read_text_if_exists(path / "readme.md"),
|
|
66
|
+
_read_text_if_exists(path / "Dockerfile"),
|
|
67
|
+
_read_text_if_exists(path / "setup.py"),
|
|
68
|
+
_read_text_if_exists(path / "pyproject.toml"),
|
|
69
|
+
]
|
|
70
|
+
).lower()
|
|
71
|
+
|
|
72
|
+
if any(keyword in searchable_text for keyword in SYSTEM_KEYWORDS):
|
|
73
|
+
return True
|
|
74
|
+
|
|
75
|
+
cpp_suffixes = {".cpp", ".cc", ".cxx", ".c", ".hpp", ".h"}
|
|
76
|
+
|
|
77
|
+
for file_path in path.rglob("*"):
|
|
78
|
+
if ".git" in file_path.parts:
|
|
79
|
+
continue
|
|
80
|
+
|
|
81
|
+
if file_path.is_file() and file_path.suffix.lower() in cpp_suffixes:
|
|
82
|
+
return True
|
|
83
|
+
|
|
84
|
+
return False
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _ubuntu_dockerfile() -> str:
|
|
88
|
+
"""Return a Dockerfile with common simulator system packages."""
|
|
89
|
+
packages = " \\\n ".join(COMMON_SIMULATOR_APT_PACKAGES)
|
|
90
|
+
|
|
91
|
+
return f"""FROM ubuntu:22.04
|
|
92
|
+
|
|
93
|
+
SHELL ["/bin/bash", "-c"]
|
|
94
|
+
|
|
95
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
|
96
|
+
|
|
97
|
+
RUN apt-get update && apt-get install -y \\
|
|
98
|
+
{packages} \\
|
|
99
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
100
|
+
|
|
101
|
+
WORKDIR /workspace
|
|
102
|
+
|
|
103
|
+
COPY . /workspace
|
|
104
|
+
|
|
105
|
+
CMD ["/bin/bash"]
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _extract_existing_apt_packages(dockerfile_text: str) -> set[str]:
|
|
110
|
+
"""Extract simple package names already present in a Dockerfile."""
|
|
111
|
+
existing_packages: set[str] = set()
|
|
112
|
+
|
|
113
|
+
for package in COMMON_SIMULATOR_APT_PACKAGES:
|
|
114
|
+
if package in dockerfile_text:
|
|
115
|
+
existing_packages.add(package)
|
|
116
|
+
|
|
117
|
+
return existing_packages
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _append_apt_install_block(dockerfile_text: str, packages: list[str]) -> str:
|
|
121
|
+
"""Append an apt-get install block to an existing Dockerfile."""
|
|
122
|
+
package_lines = " \\\n ".join(packages)
|
|
123
|
+
|
|
124
|
+
block = f"""
|
|
125
|
+
|
|
126
|
+
# Added by SimFix: common simulator system dependencies
|
|
127
|
+
RUN apt-get update && apt-get install -y \\
|
|
128
|
+
{package_lines} \\
|
|
129
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
return dockerfile_text.rstrip() + block + "\n"
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def fix_system_dockerfile(repo_path: str | Path) -> SystemDockerFixResult | None:
|
|
136
|
+
"""Create or update Dockerfile with common simulator system packages."""
|
|
137
|
+
path = Path(repo_path).expanduser().resolve()
|
|
138
|
+
|
|
139
|
+
if not detect_system_dependency_project(path):
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
dockerfile_path = path / "Dockerfile"
|
|
143
|
+
|
|
144
|
+
if not dockerfile_path.exists():
|
|
145
|
+
dockerfile_path.write_text(_ubuntu_dockerfile(), encoding="utf-8")
|
|
146
|
+
|
|
147
|
+
return SystemDockerFixResult(
|
|
148
|
+
file_path=dockerfile_path,
|
|
149
|
+
changed=True,
|
|
150
|
+
message="Created Dockerfile with common simulator system packages.",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
old_text = dockerfile_path.read_text(encoding="utf-8")
|
|
154
|
+
existing_packages = _extract_existing_apt_packages(old_text)
|
|
155
|
+
missing_packages = [
|
|
156
|
+
package
|
|
157
|
+
for package in COMMON_SIMULATOR_APT_PACKAGES
|
|
158
|
+
if package not in existing_packages
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
if not missing_packages:
|
|
162
|
+
return SystemDockerFixResult(
|
|
163
|
+
file_path=dockerfile_path,
|
|
164
|
+
changed=False,
|
|
165
|
+
message="Dockerfile already contains common simulator system packages.",
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
new_text = _append_apt_install_block(old_text, missing_packages)
|
|
169
|
+
dockerfile_path.write_text(new_text, encoding="utf-8")
|
|
170
|
+
|
|
171
|
+
return SystemDockerFixResult(
|
|
172
|
+
file_path=dockerfile_path,
|
|
173
|
+
changed=True,
|
|
174
|
+
message="Updated Dockerfile with missing simulator system packages.",
|
|
175
|
+
)
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simfix
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A dependency checker and installation assistant for simulator repositories.
|
|
5
|
+
Author-email: Habib ur Rehmaan <h.rehmaan96@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/hrehmaan/simfix
|
|
8
|
+
Project-URL: Repository, https://github.com/hrehmaan/simfix
|
|
9
|
+
Project-URL: Issues, https://github.com/hrehmaan/simfix/issues
|
|
10
|
+
Keywords: simulator,dependencies,installation,docker,cuda,ros
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: rich
|
|
24
|
+
Requires-Dist: typer
|
|
25
|
+
Requires-Dist: requests
|
|
26
|
+
Requires-Dist: packaging
|
|
27
|
+
Requires-Dist: pyyaml
|
|
28
|
+
Requires-Dist: uv
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest; extra == "dev"
|
|
31
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# SimFix
|
|
36
|
+
|
|
37
|
+
SimFix is a dependency checker and installation assistant for simulator repositories.
|
|
38
|
+
|
|
39
|
+
It helps users diagnose common installation problems by inspecting repository files, detecting dependency systems, checking Python packages, identifying system requirements, and suggesting a safe installation plan.
|
|
40
|
+
|
|
41
|
+
SimFix is designed for simulator projects where installation can fail because of missing dependencies, version conflicts, GPU/CUDA requirements, ROS dependencies, Docker setup issues, or unclear setup instructions.
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
SimFix can analyze both local repositories and remote GitHub/GitLab repositories.
|
|
46
|
+
|
|
47
|
+
It currently supports:
|
|
48
|
+
|
|
49
|
+
* Local repository analysis
|
|
50
|
+
* GitHub/GitLab repository analysis by cloning into a local workspace
|
|
51
|
+
* Dependency file detection
|
|
52
|
+
* Python dependency parsing
|
|
53
|
+
* PyPI package checks
|
|
54
|
+
* Basic installation planning
|
|
55
|
+
* System diagnostics
|
|
56
|
+
* Safe dependency fixes for selected file types
|
|
57
|
+
* Docker helper generation for supported simulator projects
|
|
58
|
+
|
|
59
|
+
## Supported dependency files
|
|
60
|
+
|
|
61
|
+
SimFix can detect and inspect:
|
|
62
|
+
|
|
63
|
+
* `requirements.txt`
|
|
64
|
+
* `setup.py`
|
|
65
|
+
* `pyproject.toml`
|
|
66
|
+
* `environment.yml` / `environment.yaml`
|
|
67
|
+
* `Dockerfile`
|
|
68
|
+
* `package.xml`
|
|
69
|
+
* `CMakeLists.txt`
|
|
70
|
+
|
|
71
|
+
## System diagnostics
|
|
72
|
+
|
|
73
|
+
SimFix can report:
|
|
74
|
+
|
|
75
|
+
* Operating system
|
|
76
|
+
* CPU architecture
|
|
77
|
+
* Python version
|
|
78
|
+
* Git availability
|
|
79
|
+
* Docker availability
|
|
80
|
+
* Conda/mamba availability
|
|
81
|
+
* NVIDIA GPU availability
|
|
82
|
+
* NVIDIA driver information
|
|
83
|
+
* CUDA toolkit availability
|
|
84
|
+
|
|
85
|
+
## Automatic fixes
|
|
86
|
+
|
|
87
|
+
The `simfix fix` command currently supports:
|
|
88
|
+
|
|
89
|
+
* Resolving `requirements.txt` with `uv`
|
|
90
|
+
* Normalizing invalid pip syntax such as `package=version` to `package==version`
|
|
91
|
+
* Repairing clear resolver conflicts by removing direct conflicting pins and letting `uv` choose compatible versions
|
|
92
|
+
* Cleaning duplicate dependencies in `environment.yml`
|
|
93
|
+
* Creating CUDA/GPU Dockerfiles for GPU-based simulator projects
|
|
94
|
+
* Creating ROS Dockerfiles from `package.xml`
|
|
95
|
+
* Creating general system dependency Dockerfiles for CMake/C++ simulator projects
|
|
96
|
+
* Initializing Git submodules
|
|
97
|
+
* Pulling Git LFS assets when Git LFS is available
|
|
98
|
+
* Creating a Docker run helper script
|
|
99
|
+
|
|
100
|
+
For GPU projects, SimFix can create a CUDA-based Dockerfile. The host machine still needs a working NVIDIA driver and NVIDIA Container Toolkit to run GPU containers.
|
|
101
|
+
|
|
102
|
+
SimFix does not automatically install vendor software such as NVIDIA Isaac Gym, Isaac Sim, CUDA drivers, or system-level GPU drivers. These dependencies must be installed manually.
|
|
103
|
+
|
|
104
|
+
## Installation for development
|
|
105
|
+
|
|
106
|
+
Clone the repository:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git clone https://github.com/hrehmaan/simfix.git
|
|
110
|
+
cd simfix
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Install in editable mode with development dependencies:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
python -m pip install -e ".[dev]"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Install pre-commit hooks:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
pre-commit install
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Usage
|
|
126
|
+
|
|
127
|
+
Check your system:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
simfix system
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Analyze a repository:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
simfix doctor <repo>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Example:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
simfix doctor ../simfix_test
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Analyze a repository and show detected metadata:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
simfix analyze <repo>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Generate an installation plan:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
simfix plan <repo>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Generate a Markdown report:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
simfix doctor <repo> --report
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Show suggested installation commands without running them:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
simfix commands <repo>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Apply supported automatic fixes:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
simfix fix <repo>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Analyze a remote GitHub repository:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
simfix doctor https://github.com/hrehmaan/simfix.git
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Show the installed SimFix version:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
simfix version
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Main commands
|
|
188
|
+
|
|
189
|
+
```text
|
|
190
|
+
simfix system
|
|
191
|
+
simfix doctor <repo>
|
|
192
|
+
simfix doctor <repo> --report
|
|
193
|
+
simfix analyze <repo>
|
|
194
|
+
simfix plan <repo>
|
|
195
|
+
simfix commands <repo>
|
|
196
|
+
simfix fix <repo>
|
|
197
|
+
simfix version
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Example output
|
|
201
|
+
|
|
202
|
+
```text
|
|
203
|
+
SimFix Doctor
|
|
204
|
+
Repository: /path/to/repository
|
|
205
|
+
|
|
206
|
+
Detected dependency files
|
|
207
|
+
requirements.txt: yes
|
|
208
|
+
setup.py: yes
|
|
209
|
+
pyproject.toml: no
|
|
210
|
+
environment.yml: no
|
|
211
|
+
Dockerfile: no
|
|
212
|
+
package.xml / ROS: no
|
|
213
|
+
CMakeLists.txt: no
|
|
214
|
+
|
|
215
|
+
Detected ecosystem(s): python
|
|
216
|
+
|
|
217
|
+
Python packages
|
|
218
|
+
- numpy
|
|
219
|
+
- matplotlib
|
|
220
|
+
|
|
221
|
+
PyPI check
|
|
222
|
+
- numpy: found
|
|
223
|
+
- matplotlib: found
|
|
224
|
+
|
|
225
|
+
Install plan
|
|
226
|
+
Recommended mode: python
|
|
227
|
+
Reason: Python dependency files were found.
|
|
228
|
+
|
|
229
|
+
Recommendation:
|
|
230
|
+
Python environment installation is possible.
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Example: fixing a Python dependency conflict
|
|
234
|
+
|
|
235
|
+
If a repository contains conflicting Python requirements such as:
|
|
236
|
+
|
|
237
|
+
```text
|
|
238
|
+
urdfpy==0.0.22
|
|
239
|
+
networkx==3.1
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
and the resolver reports that `urdfpy==0.0.22` requires `networkx==2.2`, SimFix does not blindly choose a version itself.
|
|
243
|
+
|
|
244
|
+
Instead, SimFix removes the direct conflicting pin and lets `uv` resolve the compatible version.
|
|
245
|
+
|
|
246
|
+
This keeps the resolver as the authority and avoids hard-coding risky downgrades.
|
|
247
|
+
|
|
248
|
+
## Example: vendor dependency detection
|
|
249
|
+
|
|
250
|
+
Some simulator dependencies are not available on PyPI. For example, NVIDIA Isaac Gym is a vendor dependency and cannot be installed with:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
python -m pip install isaacgym
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
In such cases, SimFix reports the missing package and indicates that manual installation is required.
|
|
257
|
+
|
|
258
|
+
For these projects, the correct setup may require:
|
|
259
|
+
|
|
260
|
+
* Linux
|
|
261
|
+
* NVIDIA GPU
|
|
262
|
+
* NVIDIA driver
|
|
263
|
+
* CUDA support
|
|
264
|
+
* Vendor SDK installation
|
|
265
|
+
|
|
266
|
+
## Development checks
|
|
267
|
+
|
|
268
|
+
Run tests:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
pytest
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Run pre-commit:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
pre-commit run --all-files
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Project status
|
|
281
|
+
|
|
282
|
+
SimFix is in early development.
|
|
283
|
+
|
|
284
|
+
The current focus is safe repository analysis, dependency diagnosis, installation planning, and targeted automatic fixes for common simulator setup problems.
|
|
285
|
+
|
|
286
|
+
The long-term goal is to make simulator setup easier by combining repository analysis, system diagnostics, dependency checks, resolver-based repair, Docker guidance, and clear manual-install warnings for vendor dependencies.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
simfix/__init__.py,sha256=8k1mftlTzNljZZcb91RxvL7xfWram4WcyZKeVLYPxt0,45
|
|
2
|
+
simfix/analyzer.py,sha256=WMlekYc0wVGJOgmiwsduQqit9pL6vqdRt8ClOl_KlQk,4272
|
|
3
|
+
simfix/cli.py,sha256=4qBwz6TuLmMOfNyvDLQnqpJtRFAYGcxrUx8A64-B3yw,14706
|
|
4
|
+
simfix/cmake.py,sha256=VZvOR9YCexAFJJ-bx7QtZ5Q9BVoO7Fu_hcKotbNbLrc,1553
|
|
5
|
+
simfix/commands.py,sha256=MmGKK_Cvw7eZZD-u6IQPSmeJbWhX7mLIYzY22yY0nE8,2734
|
|
6
|
+
simfix/compatibility.py,sha256=vDZCHRY80fkTxpiNY_8VuOD_yJgefphrnyHreCn_6-I,2929
|
|
7
|
+
simfix/conda_environment.py,sha256=gfUEEb5LZxvkxs_J_5h444go7ZJKIMObayqBSiRMPKc,1662
|
|
8
|
+
simfix/conda_fixer.py,sha256=9Qey77bFq3KHTSSVfsNm75E_o_JJxXoP37UfoASu-Nk,4370
|
|
9
|
+
simfix/cuda_docker.py,sha256=yZzyE_eWAFmJ6rJr954xjvx5b0uT09K0C_OqGV_r_LY,4203
|
|
10
|
+
simfix/docker_runner.py,sha256=XV0olJov9d-c6KHOmIbukTC7qAxOx7U2i61HXoxvd6c,1780
|
|
11
|
+
simfix/dockerfile.py,sha256=2tcPdy7FvwyuiQgy0Q71cXTni6FcakG8Fq_cy9tTbzU,3292
|
|
12
|
+
simfix/fixer.py,sha256=5IDzcZ_7mn2z7wXk4E1ofEvKIVUEOJbhY2X2mnGi5Lg,10379
|
|
13
|
+
simfix/git_assets.py,sha256=HUn_74zQ3mXH_YkCGLGE9HQIgjXZnvn3z39A3f022dA,3052
|
|
14
|
+
simfix/planner.py,sha256=kR3q8FFgyvyhphPKHToJh1P-MwAX3tbb743WgsKCOiA,3038
|
|
15
|
+
simfix/pypi.py,sha256=IWfS_6CKmEOh9poocjMErMt-iyw6uVeynkgRk6lMeo0,2062
|
|
16
|
+
simfix/pyproject.py,sha256=5711LTNXK2stUy-pbxhyqLXN69u-lwZjWnVKCm-0s1U,3477
|
|
17
|
+
simfix/python_requirements.py,sha256=d5bIvrvTBV-zwCLJe1SvPvhx-8EZb-iRv-4m4r2ApgE,1111
|
|
18
|
+
simfix/repo.py,sha256=93-Dzk0yor6AUii7fvjzFr-xAM7WXDMicm6cHgIj3L0,1294
|
|
19
|
+
simfix/report.py,sha256=IhaESMkHKo_2Kghm73JKTbnt9NoRAWZ_kws_fH3MIOw,6639
|
|
20
|
+
simfix/ros_docker.py,sha256=aHOq227zSHUzXfUt1kw4jQiEysVJG3oDcotkS0ANQbo,2648
|
|
21
|
+
simfix/ros_package.py,sha256=FGiYZAdBTjbpPlI0YePbbtW06Yd8b7wFyUmMaNqEFr8,2553
|
|
22
|
+
simfix/setup_py.py,sha256=axRXcyBfD6gXUMCLhbaUyCCRv0XPfESduFq65aCs0LY,1169
|
|
23
|
+
simfix/system.py,sha256=Altbdp5e206xqDjoW3gDGTOm-mMtCMQ0DGNYZmMi1wM,4194
|
|
24
|
+
simfix/system_docker.py,sha256=_R4s2rolP0mFnvOsa6c1hopEMVG9-FRjuRGs7O_pqtM,4566
|
|
25
|
+
simfix-0.1.0.dist-info/licenses/LICENSE,sha256=BckJViUgN8-Q78X2YBxAh4R7oAUJN8jNf2sVQGpeyUg,1073
|
|
26
|
+
simfix-0.1.0.dist-info/METADATA,sha256=YwmbPDCsy-kcqkYxf5nS_uRwZdL8j7GYO07KHcxar6c,6882
|
|
27
|
+
simfix-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
28
|
+
simfix-0.1.0.dist-info/entry_points.txt,sha256=O5Co5CiVZD80Sl-YeWhyeeZh9xEmOa2BoHKcpGfGtcU,42
|
|
29
|
+
simfix-0.1.0.dist-info/top_level.txt,sha256=8Z9xmi4Ty3l4xHmbebT6jnGG8W2VIj5kfw-N4OBwsUA,7
|
|
30
|
+
simfix-0.1.0.dist-info/RECORD,,
|