simfix 0.1.4__tar.gz → 0.1.5__tar.gz
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-0.1.4/simfix.egg-info → simfix-0.1.5}/PKG-INFO +2 -1
- {simfix-0.1.4 → simfix-0.1.5}/pyproject.toml +2 -1
- {simfix-0.1.4 → simfix-0.1.5}/simfix/__init__.py +1 -1
- {simfix-0.1.4 → simfix-0.1.5}/simfix/analyzer.py +45 -17
- {simfix-0.1.4 → simfix-0.1.5}/simfix/cli.py +10 -0
- simfix-0.1.5/simfix/commands.py +130 -0
- simfix-0.1.5/simfix/dependency_discovery.py +139 -0
- simfix-0.1.5/simfix/install_commands.py +163 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/recommendations.py +0 -36
- {simfix-0.1.4 → simfix-0.1.5}/simfix/ros_environment.py +50 -21
- {simfix-0.1.4 → simfix-0.1.5/simfix.egg-info}/PKG-INFO +2 -1
- {simfix-0.1.4 → simfix-0.1.5}/simfix.egg-info/SOURCES.txt +2 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix.egg-info/requires.txt +3 -0
- {simfix-0.1.4 → simfix-0.1.5}/tests/test_basic.py +47 -13
- simfix-0.1.4/simfix/commands.py +0 -91
- {simfix-0.1.4 → simfix-0.1.5}/LICENSE +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/README.md +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/setup.cfg +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/cmake.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/compatibility.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/conda_environment.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/conda_fixer.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/cuda.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/cuda_docker.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/docker_runner.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/dockerfile.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/fixer.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/git_assets.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/planner.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/pypi.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/pyproject.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/python_requirements.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/recommendation_types.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/repo.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/report.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/ros_docker.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/ros_package.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/setup_py.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/system.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/system_capabilities.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/system_docker.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix/vendor_dependencies.py +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix.egg-info/dependency_links.txt +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix.egg-info/entry_points.txt +0 -0
- {simfix-0.1.4 → simfix-0.1.5}/simfix.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simfix
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: A dependency checker and installation assistant for simulator repositories.
|
|
5
5
|
Author-email: Habib ur Rehmaan <h.rehmaan96@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -26,6 +26,7 @@ Requires-Dist: requests
|
|
|
26
26
|
Requires-Dist: packaging
|
|
27
27
|
Requires-Dist: pyyaml
|
|
28
28
|
Requires-Dist: uv
|
|
29
|
+
Requires-Dist: tomli; python_version < "3.11"
|
|
29
30
|
Provides-Extra: dev
|
|
30
31
|
Requires-Dist: pytest; extra == "dev"
|
|
31
32
|
Requires-Dist: pre-commit; extra == "dev"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simfix"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.5"
|
|
8
8
|
description = "A dependency checker and installation assistant for simulator repositories."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -39,6 +39,7 @@ dependencies = [
|
|
|
39
39
|
"packaging",
|
|
40
40
|
"pyyaml",
|
|
41
41
|
"uv",
|
|
42
|
+
"tomli; python_version < '3.11'",
|
|
42
43
|
]
|
|
43
44
|
|
|
44
45
|
[project.optional-dependencies]
|
|
@@ -10,6 +10,7 @@ from simfix.pypi import normalize_requirement_name
|
|
|
10
10
|
from simfix.pyproject import PyProjectInfo, parse_pyproject
|
|
11
11
|
from simfix.python_requirements import parse_requirements_file
|
|
12
12
|
from simfix.ros_package import ROSPackageInfo, parse_ros_package
|
|
13
|
+
from simfix.dependency_discovery import discover_dependency_files
|
|
13
14
|
from simfix.setup_py import parse_setup_py_dependencies
|
|
14
15
|
|
|
15
16
|
|
|
@@ -89,33 +90,60 @@ def analyze_repo(repo_path: str | Path) -> RepoAnalysis:
|
|
|
89
90
|
if not path.is_dir():
|
|
90
91
|
raise NotADirectoryError(f"Repository path is not a directory: {path}")
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
discovered_files = discover_dependency_files(path)
|
|
94
|
+
|
|
95
|
+
requirements_path = (
|
|
96
|
+
discovered_files.requirements_txt[0]
|
|
97
|
+
if discovered_files.requirements_txt
|
|
98
|
+
else path / "requirements.txt"
|
|
99
|
+
)
|
|
100
|
+
environment_path = (
|
|
101
|
+
discovered_files.environment_files[0]
|
|
102
|
+
if discovered_files.environment_files
|
|
103
|
+
else path / "environment.yml"
|
|
104
|
+
)
|
|
105
|
+
dockerfile_path = (
|
|
106
|
+
discovered_files.dockerfiles[0]
|
|
107
|
+
if discovered_files.dockerfiles
|
|
108
|
+
else path / "Dockerfile"
|
|
109
|
+
)
|
|
110
|
+
package_xml_path = (
|
|
111
|
+
discovered_files.package_xml_files[0]
|
|
112
|
+
if discovered_files.package_xml_files
|
|
113
|
+
else path / "package.xml"
|
|
114
|
+
)
|
|
115
|
+
cmake_path = (
|
|
116
|
+
discovered_files.cmake_lists_files[0]
|
|
117
|
+
if discovered_files.cmake_lists_files
|
|
118
|
+
else path / "CMakeLists.txt"
|
|
119
|
+
)
|
|
120
|
+
pyproject_path = (
|
|
121
|
+
discovered_files.pyproject_toml[0]
|
|
122
|
+
if discovered_files.pyproject_toml
|
|
123
|
+
else path / "pyproject.toml"
|
|
124
|
+
)
|
|
125
|
+
setup_py_path = (
|
|
126
|
+
discovered_files.setup_py_files[0]
|
|
127
|
+
if discovered_files.setup_py_files
|
|
128
|
+
else path / "setup.py"
|
|
129
|
+
)
|
|
96
130
|
|
|
97
|
-
dockerfile_path = path / "Dockerfile"
|
|
98
|
-
package_xml_path = path / "package.xml"
|
|
99
|
-
cmake_path = path / "CMakeLists.txt"
|
|
100
|
-
pyproject_path = path / "pyproject.toml"
|
|
101
|
-
setup_py_path = path / "setup.py"
|
|
102
131
|
setup_py_dependencies = parse_setup_py_dependencies(setup_py_path)
|
|
103
132
|
|
|
104
133
|
return RepoAnalysis(
|
|
105
134
|
repo_path=path,
|
|
106
|
-
has_requirements_txt=
|
|
107
|
-
has_environment_yml=
|
|
108
|
-
or (path / "environment.yaml").exists(),
|
|
135
|
+
has_requirements_txt=discovered_files.has_requirements_txt,
|
|
136
|
+
has_environment_yml=discovered_files.has_environment_file,
|
|
109
137
|
python_requirements=parse_requirements_file(requirements_path),
|
|
110
138
|
conda_environment=parse_conda_environment(environment_path),
|
|
111
|
-
has_dockerfile=
|
|
139
|
+
has_dockerfile=discovered_files.has_dockerfile,
|
|
112
140
|
dockerfile_info=parse_dockerfile(dockerfile_path),
|
|
113
|
-
has_package_xml=
|
|
141
|
+
has_package_xml=discovered_files.has_ros_package,
|
|
114
142
|
ros_package_info=parse_ros_package(package_xml_path),
|
|
115
|
-
has_cmake=
|
|
143
|
+
has_cmake=discovered_files.has_cmake_lists,
|
|
116
144
|
cmake_info=parse_cmake_file(cmake_path),
|
|
117
|
-
has_pyproject_toml=
|
|
145
|
+
has_pyproject_toml=discovered_files.has_pyproject_toml,
|
|
118
146
|
pyproject_info=parse_pyproject(pyproject_path),
|
|
119
|
-
has_setup_py=
|
|
147
|
+
has_setup_py=discovered_files.has_setup_py,
|
|
120
148
|
setup_py_dependencies=setup_py_dependencies,
|
|
121
149
|
)
|
|
@@ -214,6 +214,7 @@ def doctor(
|
|
|
214
214
|
console.print(f"[bold]Detected ecosystem(s):[/bold] {ecosystems}")
|
|
215
215
|
|
|
216
216
|
python_dependencies = analysis.all_python_dependencies
|
|
217
|
+
pypi_results = []
|
|
217
218
|
|
|
218
219
|
if python_dependencies:
|
|
219
220
|
deps_table = Table(title="Python packages")
|
|
@@ -224,6 +225,15 @@ def doctor(
|
|
|
224
225
|
|
|
225
226
|
console.print(deps_table)
|
|
226
227
|
|
|
228
|
+
pypi_table = Table(title="PyPI check")
|
|
229
|
+
pypi_table.add_column("Package", style="cyan")
|
|
230
|
+
pypi_table.add_column("Status")
|
|
231
|
+
|
|
232
|
+
for result in pypi_results:
|
|
233
|
+
status = "found" if result.exists else "not found"
|
|
234
|
+
pypi_table.add_row(result.name, status)
|
|
235
|
+
|
|
236
|
+
console.print(pypi_table)
|
|
227
237
|
pypi_results = check_pypi_packages(python_dependencies)
|
|
228
238
|
|
|
229
239
|
pypi_table = Table(title="PyPI check")
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from simfix.analyzer import RepoAnalysis
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class CommandPlan:
|
|
10
|
+
"""Suggested shell commands for installing a repository."""
|
|
11
|
+
|
|
12
|
+
title: str
|
|
13
|
+
commands: list[str]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def create_command_plan(analysis: RepoAnalysis) -> CommandPlan:
|
|
17
|
+
"""Create suggested installation commands from repository analysis."""
|
|
18
|
+
ecosystems = analysis.detected_ecosystems
|
|
19
|
+
repo_name = analysis.repo_path.name.replace("_", "-").lower()
|
|
20
|
+
commands: list[str] = []
|
|
21
|
+
|
|
22
|
+
if "docker" in ecosystems:
|
|
23
|
+
commands.append(f"docker build -t {repo_name} .")
|
|
24
|
+
|
|
25
|
+
run_helper = analysis.repo_path / "run_simfix_docker.sh"
|
|
26
|
+
if run_helper.exists():
|
|
27
|
+
commands.append("./run_simfix_docker.sh")
|
|
28
|
+
else:
|
|
29
|
+
commands.append(f"docker run --rm -it {repo_name}")
|
|
30
|
+
|
|
31
|
+
if "ros" in ecosystems:
|
|
32
|
+
build_system = analysis.ros_package_info.build_system.lower()
|
|
33
|
+
|
|
34
|
+
commands.extend(
|
|
35
|
+
[
|
|
36
|
+
"rosdep update",
|
|
37
|
+
"rosdep install --from-paths . --ignore-src -r -y",
|
|
38
|
+
]
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if build_system == "catkin":
|
|
42
|
+
commands.extend(
|
|
43
|
+
[
|
|
44
|
+
"catkin build",
|
|
45
|
+
"source devel/setup.bash",
|
|
46
|
+
]
|
|
47
|
+
)
|
|
48
|
+
elif build_system in {"ament", "ament_cmake", "ament_python"}:
|
|
49
|
+
commands.extend(
|
|
50
|
+
[
|
|
51
|
+
"colcon build",
|
|
52
|
+
"source install/setup.bash",
|
|
53
|
+
]
|
|
54
|
+
)
|
|
55
|
+
else:
|
|
56
|
+
commands.extend(
|
|
57
|
+
[
|
|
58
|
+
"catkin build # or: colcon build, depending on the ROS package type",
|
|
59
|
+
"source devel/setup.bash # or: source install/setup.bash",
|
|
60
|
+
]
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
if "conda" in ecosystems:
|
|
64
|
+
env_name = "simfix-env"
|
|
65
|
+
if analysis.conda_environment is not None and analysis.conda_environment.name:
|
|
66
|
+
env_name = analysis.conda_environment.name
|
|
67
|
+
|
|
68
|
+
commands.extend(
|
|
69
|
+
[
|
|
70
|
+
"conda env create -f environment.yml",
|
|
71
|
+
f"conda activate {env_name}",
|
|
72
|
+
]
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
if "python" in ecosystems:
|
|
76
|
+
commands.extend(
|
|
77
|
+
[
|
|
78
|
+
"python -m venv .venv",
|
|
79
|
+
"source .venv/bin/activate",
|
|
80
|
+
"python -m pip install --upgrade pip",
|
|
81
|
+
]
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
if analysis.has_requirements_txt:
|
|
85
|
+
commands.append("python -m pip install -r requirements.txt")
|
|
86
|
+
|
|
87
|
+
if analysis.has_pyproject_toml or analysis.has_setup_py:
|
|
88
|
+
commands.extend(
|
|
89
|
+
[
|
|
90
|
+
"python -m pip install -e .",
|
|
91
|
+
"python -m pip install -e . --no-deps # use only if vendor/manual dependencies block normal install",
|
|
92
|
+
]
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
if "cmake/c++" in ecosystems and "ros" not in ecosystems:
|
|
96
|
+
commands.extend(
|
|
97
|
+
[
|
|
98
|
+
"cmake -S . -B build",
|
|
99
|
+
"cmake --build build -j",
|
|
100
|
+
]
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
if not commands:
|
|
104
|
+
commands.extend(
|
|
105
|
+
[
|
|
106
|
+
"# No common dependency file was detected.",
|
|
107
|
+
"# Read the README installation section manually.",
|
|
108
|
+
"# Check for install scripts such as install.sh or setup.sh.",
|
|
109
|
+
]
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
return CommandPlan(
|
|
113
|
+
title="Suggested installation commands",
|
|
114
|
+
commands=_deduplicate_commands(commands),
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _deduplicate_commands(commands: list[str]) -> list[str]:
|
|
119
|
+
"""Return commands without duplicates while preserving order."""
|
|
120
|
+
seen: set[str] = set()
|
|
121
|
+
unique_commands: list[str] = []
|
|
122
|
+
|
|
123
|
+
for command in commands:
|
|
124
|
+
if command in seen:
|
|
125
|
+
continue
|
|
126
|
+
|
|
127
|
+
seen.add(command)
|
|
128
|
+
unique_commands.append(command)
|
|
129
|
+
|
|
130
|
+
return unique_commands
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Generic dependency-file discovery for simulator repositories."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
IGNORED_DIRECTORY_NAMES = {
|
|
10
|
+
".git",
|
|
11
|
+
".hg",
|
|
12
|
+
".svn",
|
|
13
|
+
".venv",
|
|
14
|
+
"venv",
|
|
15
|
+
"env",
|
|
16
|
+
"__pycache__",
|
|
17
|
+
".mypy_cache",
|
|
18
|
+
".ruff_cache",
|
|
19
|
+
".pytest_cache",
|
|
20
|
+
"build",
|
|
21
|
+
"dist",
|
|
22
|
+
"install",
|
|
23
|
+
"log",
|
|
24
|
+
"node_modules",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
DEPENDENCY_FILE_NAMES = {
|
|
29
|
+
"requirements.txt",
|
|
30
|
+
"pyproject.toml",
|
|
31
|
+
"environment.yml",
|
|
32
|
+
"environment.yaml",
|
|
33
|
+
"Dockerfile",
|
|
34
|
+
"package.xml",
|
|
35
|
+
"CMakeLists.txt",
|
|
36
|
+
"setup.py",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True)
|
|
41
|
+
class DiscoveredDependencyFiles:
|
|
42
|
+
"""Dependency files discovered in a repository."""
|
|
43
|
+
|
|
44
|
+
requirements_txt: tuple[Path, ...]
|
|
45
|
+
pyproject_toml: tuple[Path, ...]
|
|
46
|
+
environment_files: tuple[Path, ...]
|
|
47
|
+
dockerfiles: tuple[Path, ...]
|
|
48
|
+
package_xml_files: tuple[Path, ...]
|
|
49
|
+
cmake_lists_files: tuple[Path, ...]
|
|
50
|
+
setup_py_files: tuple[Path, ...]
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def has_requirements_txt(self) -> bool:
|
|
54
|
+
return bool(self.requirements_txt)
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def has_pyproject_toml(self) -> bool:
|
|
58
|
+
return bool(self.pyproject_toml)
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def has_environment_file(self) -> bool:
|
|
62
|
+
return bool(self.environment_files)
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def has_dockerfile(self) -> bool:
|
|
66
|
+
return bool(self.dockerfiles)
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def has_ros_package(self) -> bool:
|
|
70
|
+
return bool(self.package_xml_files)
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def has_cmake_lists(self) -> bool:
|
|
74
|
+
return bool(self.cmake_lists_files)
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def has_setup_py(self) -> bool:
|
|
78
|
+
return bool(self.setup_py_files)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def discover_dependency_files(
|
|
82
|
+
repo_path: Path,
|
|
83
|
+
*,
|
|
84
|
+
max_depth: int = 4,
|
|
85
|
+
) -> DiscoveredDependencyFiles:
|
|
86
|
+
"""Discover dependency files in a repository up to a safe depth.
|
|
87
|
+
|
|
88
|
+
This is generic and does not assume a specific simulator layout.
|
|
89
|
+
It intentionally skips common build, cache, virtualenv, and VCS folders.
|
|
90
|
+
"""
|
|
91
|
+
discovered_files = _walk_dependency_files(repo_path, max_depth=max_depth)
|
|
92
|
+
|
|
93
|
+
return DiscoveredDependencyFiles(
|
|
94
|
+
requirements_txt=_filter_by_name(discovered_files, "requirements.txt"),
|
|
95
|
+
pyproject_toml=_filter_by_name(discovered_files, "pyproject.toml"),
|
|
96
|
+
environment_files=tuple(
|
|
97
|
+
path
|
|
98
|
+
for path in discovered_files
|
|
99
|
+
if path.name in {"environment.yml", "environment.yaml"}
|
|
100
|
+
),
|
|
101
|
+
dockerfiles=_filter_by_name(discovered_files, "Dockerfile"),
|
|
102
|
+
package_xml_files=_filter_by_name(discovered_files, "package.xml"),
|
|
103
|
+
cmake_lists_files=_filter_by_name(discovered_files, "CMakeLists.txt"),
|
|
104
|
+
setup_py_files=_filter_by_name(discovered_files, "setup.py"),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _walk_dependency_files(repo_path: Path, *, max_depth: int) -> tuple[Path, ...]:
|
|
109
|
+
repo_path = repo_path.resolve()
|
|
110
|
+
found: list[Path] = []
|
|
111
|
+
|
|
112
|
+
for path in repo_path.rglob("*"):
|
|
113
|
+
if not path.is_file():
|
|
114
|
+
continue
|
|
115
|
+
|
|
116
|
+
relative_path = path.relative_to(repo_path)
|
|
117
|
+
|
|
118
|
+
if _should_skip_path(relative_path):
|
|
119
|
+
continue
|
|
120
|
+
|
|
121
|
+
if _depth(relative_path) > max_depth:
|
|
122
|
+
continue
|
|
123
|
+
|
|
124
|
+
if path.name in DEPENDENCY_FILE_NAMES:
|
|
125
|
+
found.append(path)
|
|
126
|
+
|
|
127
|
+
return tuple(sorted(found))
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _filter_by_name(paths: tuple[Path, ...], name: str) -> tuple[Path, ...]:
|
|
131
|
+
return tuple(path for path in paths if path.name == name)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _should_skip_path(relative_path: Path) -> bool:
|
|
135
|
+
return any(part in IGNORED_DIRECTORY_NAMES for part in relative_path.parts)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _depth(relative_path: Path) -> int:
|
|
139
|
+
return len(relative_path.parts) - 1
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""Actionable install command generation for SimFix."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
from simfix.repo import RepoAnalysis
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class CommandGroup:
|
|
12
|
+
"""A group of related install commands."""
|
|
13
|
+
|
|
14
|
+
title: str
|
|
15
|
+
commands: tuple[str, ...]
|
|
16
|
+
note: str | None = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def generate_install_command_groups(analysis: RepoAnalysis) -> list[CommandGroup]:
|
|
20
|
+
"""Generate actionable install commands from detected repository metadata.
|
|
21
|
+
|
|
22
|
+
The logic is generic and based on detected ecosystems/files, not repository names.
|
|
23
|
+
"""
|
|
24
|
+
command_groups: list[CommandGroup] = []
|
|
25
|
+
|
|
26
|
+
if analysis.has_dockerfile:
|
|
27
|
+
command_groups.append(_docker_commands())
|
|
28
|
+
|
|
29
|
+
if analysis.has_package_xml:
|
|
30
|
+
command_groups.append(_ros_commands(analysis))
|
|
31
|
+
|
|
32
|
+
if analysis.has_requirements_txt:
|
|
33
|
+
command_groups.append(_python_requirements_commands())
|
|
34
|
+
|
|
35
|
+
if analysis.has_pyproject_toml or analysis.has_setup_py:
|
|
36
|
+
command_groups.append(_python_project_commands())
|
|
37
|
+
|
|
38
|
+
if analysis.has_environment_yml:
|
|
39
|
+
command_groups.append(_conda_commands())
|
|
40
|
+
|
|
41
|
+
if analysis.has_cmake and not analysis.has_package_xml:
|
|
42
|
+
command_groups.append(_cmake_commands())
|
|
43
|
+
|
|
44
|
+
if not command_groups:
|
|
45
|
+
command_groups.append(
|
|
46
|
+
CommandGroup(
|
|
47
|
+
title="Manual inspection",
|
|
48
|
+
commands=(
|
|
49
|
+
"Read the project README installation section.",
|
|
50
|
+
"Check for install scripts such as install.sh, setup.sh, or Docker instructions.",
|
|
51
|
+
"Run project examples/tests after installing dependencies.",
|
|
52
|
+
),
|
|
53
|
+
note="No common dependency files were detected.",
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return command_groups
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _docker_commands() -> CommandGroup:
|
|
61
|
+
return CommandGroup(
|
|
62
|
+
title="Docker workflow",
|
|
63
|
+
commands=(
|
|
64
|
+
"docker build -t simfix-workspace .",
|
|
65
|
+
"./run_simfix_docker.sh",
|
|
66
|
+
),
|
|
67
|
+
note=(
|
|
68
|
+
"Use this when Dockerfile/run_simfix_docker.sh exists. "
|
|
69
|
+
"For GPU projects, the host must have working NVIDIA Docker support."
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _ros_commands(analysis: RepoAnalysis) -> CommandGroup:
|
|
75
|
+
build_system = analysis.ros_package_info.build_system.lower()
|
|
76
|
+
|
|
77
|
+
if build_system == "catkin":
|
|
78
|
+
return CommandGroup(
|
|
79
|
+
title="ROS 1 / catkin workflow",
|
|
80
|
+
commands=(
|
|
81
|
+
"rosdep update",
|
|
82
|
+
"rosdep install --from-paths . --ignore-src -r -y",
|
|
83
|
+
"catkin build",
|
|
84
|
+
"source devel/setup.bash",
|
|
85
|
+
),
|
|
86
|
+
note=(
|
|
87
|
+
"Run these inside a ROS 1 workspace or inside the generated ROS Noetic Docker container."
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if build_system in {"ament_cmake", "ament_python", "ament"}:
|
|
92
|
+
return CommandGroup(
|
|
93
|
+
title="ROS 2 / colcon workflow",
|
|
94
|
+
commands=(
|
|
95
|
+
"rosdep update",
|
|
96
|
+
"rosdep install --from-paths . --ignore-src -r -y",
|
|
97
|
+
"colcon build",
|
|
98
|
+
"source install/setup.bash",
|
|
99
|
+
),
|
|
100
|
+
note=(
|
|
101
|
+
"Run these inside a ROS 2 workspace or inside a matching ROS 2 Docker container."
|
|
102
|
+
),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
return CommandGroup(
|
|
106
|
+
title="ROS workflow",
|
|
107
|
+
commands=(
|
|
108
|
+
"rosdep update",
|
|
109
|
+
"rosdep install --from-paths . --ignore-src -r -y",
|
|
110
|
+
"Build with catkin build or colcon build depending on the ROS package type.",
|
|
111
|
+
"Source the generated setup file.",
|
|
112
|
+
),
|
|
113
|
+
note="ROS package files were detected, but the build style was not classified.",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _python_requirements_commands() -> CommandGroup:
|
|
118
|
+
return CommandGroup(
|
|
119
|
+
title="Python requirements workflow",
|
|
120
|
+
commands=(
|
|
121
|
+
"python -m venv .venv",
|
|
122
|
+
"source .venv/bin/activate",
|
|
123
|
+
"python -m pip install --upgrade pip",
|
|
124
|
+
"python -m pip install -r requirements.txt",
|
|
125
|
+
),
|
|
126
|
+
note="Use this for repositories with requirements.txt.",
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _python_project_commands() -> CommandGroup:
|
|
131
|
+
return CommandGroup(
|
|
132
|
+
title="Python editable install workflow",
|
|
133
|
+
commands=(
|
|
134
|
+
"python -m pip install -e .",
|
|
135
|
+
"python -m pip install -e . --no-deps # use only if vendor/manual dependencies block normal install",
|
|
136
|
+
),
|
|
137
|
+
note=(
|
|
138
|
+
"Use --no-deps only after installing normal requirements or when vendor dependencies "
|
|
139
|
+
"must be installed manually."
|
|
140
|
+
),
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _conda_commands() -> CommandGroup:
|
|
145
|
+
return CommandGroup(
|
|
146
|
+
title="Conda environment workflow",
|
|
147
|
+
commands=(
|
|
148
|
+
"conda env create -f environment.yml",
|
|
149
|
+
"conda activate <environment-name>",
|
|
150
|
+
),
|
|
151
|
+
note="Replace <environment-name> with the name defined inside environment.yml.",
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _cmake_commands() -> CommandGroup:
|
|
156
|
+
return CommandGroup(
|
|
157
|
+
title="CMake workflow",
|
|
158
|
+
commands=(
|
|
159
|
+
"cmake -S . -B build",
|
|
160
|
+
"cmake --build build",
|
|
161
|
+
),
|
|
162
|
+
note="Use this for non-ROS CMake/C++ projects.",
|
|
163
|
+
)
|
|
@@ -50,42 +50,6 @@ def generate_recommendations(
|
|
|
50
50
|
detect_vendor_dependency_recommendations(normalized_dependencies)
|
|
51
51
|
)
|
|
52
52
|
|
|
53
|
-
if has_isaacgym:
|
|
54
|
-
recommendations.append(
|
|
55
|
-
Recommendation(
|
|
56
|
-
category="Vendor-managed dependency",
|
|
57
|
-
title="NVIDIA Isaac Gym required",
|
|
58
|
-
status="Manual installation required",
|
|
59
|
-
reason=(
|
|
60
|
-
"The dependency 'isaacgym' was detected, but it is not "
|
|
61
|
-
"available as a normal PyPI package."
|
|
62
|
-
),
|
|
63
|
-
suggestion=(
|
|
64
|
-
"Install NVIDIA Isaac Gym manually in a compatible Linux "
|
|
65
|
-
"environment with NVIDIA GPU support. If the local machine "
|
|
66
|
-
"is not suitable, use an HPC GPU node or cloud GPU instance."
|
|
67
|
-
),
|
|
68
|
-
)
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
if has_isaacsim:
|
|
72
|
-
recommendations.append(
|
|
73
|
-
Recommendation(
|
|
74
|
-
category="Vendor-managed dependency",
|
|
75
|
-
title="NVIDIA Isaac Sim required",
|
|
76
|
-
status="Manual installation required",
|
|
77
|
-
reason=(
|
|
78
|
-
"Isaac Sim or omni.isaac dependencies were detected. "
|
|
79
|
-
"These are NVIDIA-managed dependencies."
|
|
80
|
-
),
|
|
81
|
-
suggestion=(
|
|
82
|
-
"Install Isaac Sim using NVIDIA's official installation "
|
|
83
|
-
"method. Use a supported system with compatible NVIDIA GPU "
|
|
84
|
-
"drivers."
|
|
85
|
-
),
|
|
86
|
-
)
|
|
87
|
-
)
|
|
88
|
-
|
|
89
53
|
if has_isaacgym or has_isaacsim or has_cuda_dependency:
|
|
90
54
|
recommendations.append(
|
|
91
55
|
Recommendation(
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
from simfix.dependency_discovery import discover_dependency_files
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
@dataclass(frozen=True)
|
|
@@ -21,25 +22,30 @@ def detect_ros_environment_info(repo_path: Path) -> RosEnvironmentInfo | None:
|
|
|
21
22
|
"""Detect ROS project style and recommend a common compatible environment.
|
|
22
23
|
|
|
23
24
|
This detection is generic and based on build-system signals, not repository
|
|
24
|
-
names. It
|
|
25
|
+
names. It supports both root-level ROS packages and nested ROS workspaces.
|
|
26
|
+
It does not install ROS or modify files.
|
|
25
27
|
"""
|
|
26
|
-
|
|
27
|
-
cmake_lists = repo_path / "CMakeLists.txt"
|
|
28
|
+
discovered_files = discover_dependency_files(repo_path)
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
combined_text = f"{package_text}\n{cmake_text}".lower()
|
|
30
|
+
package_xml_files = discovered_files.package_xml_files
|
|
31
|
+
cmake_lists_files = discovered_files.cmake_lists_files
|
|
32
32
|
|
|
33
|
-
if not
|
|
33
|
+
if not package_xml_files and not cmake_lists_files:
|
|
34
34
|
return None
|
|
35
35
|
|
|
36
|
+
package_text = "\n".join(_read_file(path) for path in package_xml_files)
|
|
37
|
+
cmake_text = "\n".join(_read_file(path) for path in cmake_lists_files)
|
|
38
|
+
combined_text = f"{package_text}\n{cmake_text}".lower()
|
|
39
|
+
|
|
40
|
+
source = _source_label(*package_xml_files, *cmake_lists_files)
|
|
41
|
+
|
|
36
42
|
if _looks_like_ros2(combined_text):
|
|
37
43
|
return RosEnvironmentInfo(
|
|
38
44
|
project_type="ROS 2 / ament",
|
|
39
45
|
recommended_distribution="Humble",
|
|
40
46
|
recommended_ubuntu="Ubuntu 22.04",
|
|
41
47
|
recommended_docker_image="osrf/ros:humble-desktop",
|
|
42
|
-
source=
|
|
48
|
+
source=source,
|
|
43
49
|
)
|
|
44
50
|
|
|
45
51
|
if _looks_like_ros1(combined_text):
|
|
@@ -48,19 +54,16 @@ def detect_ros_environment_info(repo_path: Path) -> RosEnvironmentInfo | None:
|
|
|
48
54
|
recommended_distribution="Noetic",
|
|
49
55
|
recommended_ubuntu="Ubuntu 20.04",
|
|
50
56
|
recommended_docker_image="osrf/ros:noetic-desktop-full",
|
|
51
|
-
source=
|
|
57
|
+
source=source,
|
|
52
58
|
)
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
return None
|
|
60
|
+
return RosEnvironmentInfo(
|
|
61
|
+
project_type="ROS project",
|
|
62
|
+
recommended_distribution=None,
|
|
63
|
+
recommended_ubuntu=None,
|
|
64
|
+
recommended_docker_image=None,
|
|
65
|
+
source=source,
|
|
66
|
+
)
|
|
64
67
|
|
|
65
68
|
|
|
66
69
|
def _looks_like_ros2(text: str) -> bool:
|
|
@@ -97,10 +100,36 @@ def _read_file(path: Path) -> str:
|
|
|
97
100
|
return path.read_text(encoding="utf-8")
|
|
98
101
|
|
|
99
102
|
|
|
103
|
+
def _pluralize(count: int, singular: str, plural: str) -> str:
|
|
104
|
+
if count == 1:
|
|
105
|
+
return f"1 {singular}"
|
|
106
|
+
|
|
107
|
+
return f"{count} {plural}"
|
|
108
|
+
|
|
109
|
+
|
|
100
110
|
def _source_label(*paths: Path) -> str:
|
|
101
|
-
existing_paths = [path
|
|
111
|
+
existing_paths = [path for path in paths if path.exists()]
|
|
102
112
|
|
|
103
113
|
if not existing_paths:
|
|
104
114
|
return "ROS project files"
|
|
105
115
|
|
|
106
|
-
|
|
116
|
+
package_xml_count = sum(path.name == "package.xml" for path in existing_paths)
|
|
117
|
+
cmake_count = sum(path.name == "CMakeLists.txt" for path in existing_paths)
|
|
118
|
+
|
|
119
|
+
labels: list[str] = []
|
|
120
|
+
|
|
121
|
+
if package_xml_count:
|
|
122
|
+
labels.append(
|
|
123
|
+
_pluralize(package_xml_count, "package.xml file", "package.xml files")
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
if cmake_count:
|
|
127
|
+
labels.append(
|
|
128
|
+
_pluralize(cmake_count, "CMakeLists.txt file", "CMakeLists.txt files")
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if labels:
|
|
132
|
+
return " and ".join(labels)
|
|
133
|
+
|
|
134
|
+
unique_names = sorted({path.name for path in existing_paths})
|
|
135
|
+
return ", ".join(unique_names)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simfix
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: A dependency checker and installation assistant for simulator repositories.
|
|
5
5
|
Author-email: Habib ur Rehmaan <h.rehmaan96@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -26,6 +26,7 @@ Requires-Dist: requests
|
|
|
26
26
|
Requires-Dist: packaging
|
|
27
27
|
Requires-Dist: pyyaml
|
|
28
28
|
Requires-Dist: uv
|
|
29
|
+
Requires-Dist: tomli; python_version < "3.11"
|
|
29
30
|
Provides-Extra: dev
|
|
30
31
|
Requires-Dist: pytest; extra == "dev"
|
|
31
32
|
Requires-Dist: pre-commit; extra == "dev"
|
|
@@ -11,10 +11,12 @@ simfix/conda_environment.py
|
|
|
11
11
|
simfix/conda_fixer.py
|
|
12
12
|
simfix/cuda.py
|
|
13
13
|
simfix/cuda_docker.py
|
|
14
|
+
simfix/dependency_discovery.py
|
|
14
15
|
simfix/docker_runner.py
|
|
15
16
|
simfix/dockerfile.py
|
|
16
17
|
simfix/fixer.py
|
|
17
18
|
simfix/git_assets.py
|
|
19
|
+
simfix/install_commands.py
|
|
18
20
|
simfix/planner.py
|
|
19
21
|
simfix/pypi.py
|
|
20
22
|
simfix/pyproject.py
|
|
@@ -58,7 +58,7 @@ from simfix.system import (
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
def test_version() -> None:
|
|
61
|
-
assert __version__ == "0.1.
|
|
61
|
+
assert __version__ == "0.1.5"
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
def test_analyze_python_repo(tmp_path: Path) -> None:
|
|
@@ -639,8 +639,9 @@ def test_create_python_command_plan(tmp_path: Path) -> None:
|
|
|
639
639
|
analysis = analyze_repo(tmp_path)
|
|
640
640
|
command_plan = create_command_plan(analysis)
|
|
641
641
|
|
|
642
|
-
assert command_plan.title == "
|
|
642
|
+
assert command_plan.title == "Suggested installation commands"
|
|
643
643
|
assert "python -m venv .venv" in command_plan.commands
|
|
644
|
+
assert "source .venv/bin/activate" in command_plan.commands
|
|
644
645
|
assert "python -m pip install -r requirements.txt" in command_plan.commands
|
|
645
646
|
|
|
646
647
|
|
|
@@ -650,8 +651,13 @@ def test_create_docker_command_plan(tmp_path: Path) -> None:
|
|
|
650
651
|
analysis = analyze_repo(tmp_path)
|
|
651
652
|
command_plan = create_command_plan(analysis)
|
|
652
653
|
|
|
653
|
-
assert command_plan.title == "
|
|
654
|
-
assert any(
|
|
654
|
+
assert command_plan.title == "Suggested installation commands"
|
|
655
|
+
assert any(
|
|
656
|
+
command.startswith("docker build -t ") for command in command_plan.commands
|
|
657
|
+
)
|
|
658
|
+
assert any(
|
|
659
|
+
command.startswith("docker run --rm -it ") for command in command_plan.commands
|
|
660
|
+
)
|
|
655
661
|
|
|
656
662
|
|
|
657
663
|
def test_fix_requirements_with_uv_returns_none_without_requirements(
|
|
@@ -1203,7 +1209,15 @@ def test_recommendations_command_detects_isaacgym(tmp_path: Path) -> None:
|
|
|
1203
1209
|
result = runner.invoke(app, ["recommendations", str(repo)])
|
|
1204
1210
|
|
|
1205
1211
|
assert result.exit_code == 0
|
|
1206
|
-
assert "
|
|
1212
|
+
assert "SimFix Recommendations" in result.output
|
|
1213
|
+
|
|
1214
|
+
|
|
1215
|
+
def test_vendor_dependency_recommendations_detect_isaacgym() -> None:
|
|
1216
|
+
recommendations = detect_vendor_dependency_recommendations(["isaacgym"])
|
|
1217
|
+
|
|
1218
|
+
titles = [recommendation.title for recommendation in recommendations]
|
|
1219
|
+
|
|
1220
|
+
assert "NVIDIA Isaac Gym required" in titles
|
|
1207
1221
|
|
|
1208
1222
|
|
|
1209
1223
|
def test_doctor_shows_recommendations_hint_for_vendor_dependency(
|
|
@@ -1423,14 +1437,6 @@ def test_recommendations_include_ros_environment_info() -> None:
|
|
|
1423
1437
|
assert "ROS 1 / catkin environment detected" in titles
|
|
1424
1438
|
|
|
1425
1439
|
|
|
1426
|
-
def test_vendor_dependency_recommendations_detect_isaacgym() -> None:
|
|
1427
|
-
recommendations = detect_vendor_dependency_recommendations(["isaacgym"])
|
|
1428
|
-
|
|
1429
|
-
titles = [recommendation.title for recommendation in recommendations]
|
|
1430
|
-
|
|
1431
|
-
assert "NVIDIA Isaac Gym required" in titles
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
1440
|
def test_vendor_dependency_recommendations_detect_mujoco_py() -> None:
|
|
1435
1441
|
recommendations = detect_vendor_dependency_recommendations(["mujoco-py"])
|
|
1436
1442
|
|
|
@@ -1451,3 +1457,31 @@ def test_vendor_dependency_recommendations_ignore_normal_python_packages() -> No
|
|
|
1451
1457
|
recommendations = detect_vendor_dependency_recommendations(["numpy", "matplotlib"])
|
|
1452
1458
|
|
|
1453
1459
|
assert recommendations == []
|
|
1460
|
+
|
|
1461
|
+
|
|
1462
|
+
def test_detect_ros_environment_info_from_nested_workspace(tmp_path: Path) -> None:
|
|
1463
|
+
repo = tmp_path / "repo"
|
|
1464
|
+
package = repo / "planner_gazebo_sim"
|
|
1465
|
+
package.mkdir(parents=True)
|
|
1466
|
+
|
|
1467
|
+
(package / "package.xml").write_text(
|
|
1468
|
+
"""
|
|
1469
|
+
<package format="2">
|
|
1470
|
+
<name>planner_gazebo_sim</name>
|
|
1471
|
+
<buildtool_depend>catkin</buildtool_depend>
|
|
1472
|
+
<depend>roscpp</depend>
|
|
1473
|
+
</package>
|
|
1474
|
+
""",
|
|
1475
|
+
encoding="utf-8",
|
|
1476
|
+
)
|
|
1477
|
+
(package / "CMakeLists.txt").write_text(
|
|
1478
|
+
"find_package(catkin REQUIRED)",
|
|
1479
|
+
encoding="utf-8",
|
|
1480
|
+
)
|
|
1481
|
+
|
|
1482
|
+
info = detect_ros_environment_info(repo)
|
|
1483
|
+
|
|
1484
|
+
assert info is not None
|
|
1485
|
+
assert info.project_type == "ROS 1 / catkin"
|
|
1486
|
+
assert info.recommended_distribution == "Noetic"
|
|
1487
|
+
assert info.recommended_ubuntu == "Ubuntu 20.04"
|
simfix-0.1.4/simfix/commands.py
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
|
|
5
|
-
from simfix.analyzer import RepoAnalysis
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@dataclass(frozen=True)
|
|
9
|
-
class CommandPlan:
|
|
10
|
-
"""Suggested shell commands for installing a repository."""
|
|
11
|
-
|
|
12
|
-
title: str
|
|
13
|
-
commands: list[str]
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def create_command_plan(analysis: RepoAnalysis) -> CommandPlan:
|
|
17
|
-
"""Create suggested installation commands from repository analysis."""
|
|
18
|
-
ecosystems = analysis.detected_ecosystems
|
|
19
|
-
repo_name = analysis.repo_path.name.replace("_", "-").lower()
|
|
20
|
-
|
|
21
|
-
if "docker" in ecosystems:
|
|
22
|
-
return CommandPlan(
|
|
23
|
-
title="Docker installation commands",
|
|
24
|
-
commands=[
|
|
25
|
-
f"docker build -t {repo_name} .",
|
|
26
|
-
f"docker run --rm -it {repo_name}",
|
|
27
|
-
],
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
if "conda" in ecosystems:
|
|
31
|
-
env_name = "simfix-env"
|
|
32
|
-
if analysis.conda_environment is not None and analysis.conda_environment.name:
|
|
33
|
-
env_name = analysis.conda_environment.name
|
|
34
|
-
|
|
35
|
-
return CommandPlan(
|
|
36
|
-
title="Conda installation commands",
|
|
37
|
-
commands=[
|
|
38
|
-
"conda env create -f environment.yml",
|
|
39
|
-
f"conda activate {env_name}",
|
|
40
|
-
],
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
if "ros" in ecosystems:
|
|
44
|
-
return CommandPlan(
|
|
45
|
-
title="ROS installation commands",
|
|
46
|
-
commands=[
|
|
47
|
-
"mkdir -p ~/simfix_ws/src",
|
|
48
|
-
"cd ~/simfix_ws/src",
|
|
49
|
-
"# Clone or copy the repository into this src folder",
|
|
50
|
-
"cd ~/simfix_ws",
|
|
51
|
-
"rosdep install --from-paths src --ignore-src -r -y",
|
|
52
|
-
"catkin build # or: colcon build",
|
|
53
|
-
"source devel/setup.bash # or: source install/setup.bash",
|
|
54
|
-
],
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
if "python" in ecosystems:
|
|
58
|
-
commands = [
|
|
59
|
-
"python -m venv .venv",
|
|
60
|
-
"source .venv/bin/activate",
|
|
61
|
-
]
|
|
62
|
-
|
|
63
|
-
if analysis.has_requirements_txt:
|
|
64
|
-
commands.append("python -m pip install -r requirements.txt")
|
|
65
|
-
|
|
66
|
-
if analysis.has_pyproject_toml:
|
|
67
|
-
commands.append("python -m pip install -e .")
|
|
68
|
-
|
|
69
|
-
return CommandPlan(
|
|
70
|
-
title="Python installation commands",
|
|
71
|
-
commands=commands,
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
if "cmake/c++" in ecosystems:
|
|
75
|
-
return CommandPlan(
|
|
76
|
-
title="CMake installation commands",
|
|
77
|
-
commands=[
|
|
78
|
-
"mkdir -p build",
|
|
79
|
-
"cd build",
|
|
80
|
-
"cmake ..",
|
|
81
|
-
"cmake --build . -j",
|
|
82
|
-
],
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
return CommandPlan(
|
|
86
|
-
title="Manual installation commands",
|
|
87
|
-
commands=[
|
|
88
|
-
"# No common dependency file was detected.",
|
|
89
|
-
"# Read the README installation section manually.",
|
|
90
|
-
],
|
|
91
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|