Skip to content

Commit 1db9804

Browse files
committed
Merge branch 'python' of github.com:tue-robotics/tue-env into python
2 parents b697e53 + acaa021 commit 1db9804

File tree

10 files changed

+1288
-1
lines changed

10 files changed

+1288
-1
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ env
22
.rsettings
33
bin
44
user/
5+
6+
# Python install files
7+
*.egg-info

installer/tue-install-impl.bash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1527,6 +1527,6 @@ fi
15271527

15281528
TUE_INSTALL_CURRENT_TARGET="main-loop"
15291529

1530-
tue-install-echo "Installer completed succesfully"
1530+
tue-install-echo "Installer completed successfully"
15311531

15321532
return 0

setup.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import os.path
2+
3+
from setuptools import find_packages
4+
from setuptools import setup
5+
6+
with open(os.path.join(os.path.dirname(__file__), "VERSION"), "r") as f:
7+
version = f.readline().strip()
8+
9+
print(find_packages(where="src"))
10+
11+
setup(
12+
name="tue_env",
13+
packages=find_packages(where="src"),
14+
package_dir={"": "src"},
15+
package_data={"tue_get": ["src/tue_get/resources/*"]},
16+
include_package_data=True,
17+
version=version,
18+
author="Matthijs van der Burgh",
19+
author_email="[email protected]",
20+
maintainer="Matthijs van der Burgh",
21+
maintainer_email="[email protected]",
22+
url="https://github.com/tue-robotics/tue-env",
23+
keywords=["catkin"],
24+
classifiers=[
25+
"Environment :: Console",
26+
"Intended Audience :: Developers",
27+
"Programming Language :: Python",
28+
],
29+
description="Plugin for catkin_tools to enable building workspace documentation.",
30+
# entry_points={
31+
# "catkin_tools.commands.catkin.verbs": [
32+
# "document = catkin_tools_document:description",
33+
# ],
34+
# "catkin_tools.spaces": [
35+
# "docs = catkin_tools_document.spaces.docs:description",
36+
# ],
37+
# },
38+
python_version=">=3.8",
39+
install_requires=[
40+
"termcolor",
41+
"pyyaml",
42+
],
43+
)

src/tue_get/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from . import install_yaml_parser
2+
from . import installer_impl
3+
from . import util

src/tue_get/install_yaml_parser.py

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
from typing import Any, List, Mapping, Optional
2+
3+
from os import environ
4+
from functools import partial
5+
import yaml
6+
7+
from lsb_release import get_distro_information
8+
9+
ros_release = environ["TUE_ROS_DISTRO"]
10+
ubuntu_release = get_distro_information()["CODENAME"]
11+
12+
13+
def type_git(install_item: Mapping, allowed_keys: Optional[List[str]] = None) -> Mapping:
14+
"""
15+
Function to check the parsed yaml for install type git and generate the command string.
16+
17+
The structure of a git install type is:
18+
- type: git
19+
url: <REPOSITORY_URL>
20+
path: [LOCAL_CLONE_PATH]
21+
version: [BRANCH_COMMIT_TAG]
22+
23+
:param install_item: Extracted yaml component corresponding to install type git
24+
:param allowed_keys: Additional keys to allow apart from the keys defined in install type git
25+
:return: Mapping string containing repository url and optional keyword arguments target-dir and version
26+
"""
27+
28+
assert install_item["type"] == "git", f"Invalid install type '{install_item['type']}' for type 'git'"
29+
30+
keys = {"type", "url", "path", "version"}
31+
if allowed_keys:
32+
keys |= set(allowed_keys)
33+
34+
invalid_keys = [k for k in install_item.keys() if k not in keys]
35+
36+
if invalid_keys:
37+
raise KeyError(f"The following keys are invalid for install type 'git': {invalid_keys}")
38+
39+
url = install_item.get("url")
40+
target_dir = install_item.get("path")
41+
version = install_item.get("version")
42+
43+
if not url:
44+
raise KeyError("'url' is a mandatory key for install type 'git'")
45+
46+
return {"url": url, "target_dir": target_dir, "version": version}
47+
48+
49+
def catkin_git(source: Mapping) -> Mapping:
50+
"""
51+
Function to generate installation command for catkin git targets from the extracted yaml
52+
53+
The structure of a catkin git install type is:
54+
- type: catkin/ros
55+
source:
56+
type: git
57+
url: <REPOSITORY_URL>
58+
path: [LOCAL_CLONE_PATH]
59+
version: [BRANCH_COMMIT_TAG]
60+
sub-dir: [PACKAGE_SUB_DIRECTORY]
61+
62+
:param source: Extracted yaml component for the key 'source' corresponding to install type catkin/ros
63+
:return: Mapping containing the keyword arguments to the primary catkin target installation command
64+
"""
65+
66+
args = type_git(source, allowed_keys=["sub-dir"])
67+
args["source_type"] = "git"
68+
69+
args["sub_dir"] = source.get("sub-dir")
70+
71+
return args
72+
73+
74+
def installyaml_parser(installer: Any, path: str, now: bool = False) -> Mapping:
75+
with open(path) as f:
76+
try:
77+
install_items = yaml.load(f, yaml.CSafeLoader)
78+
except AttributeError:
79+
install_items = yaml.load(f, yaml.SafeLoader)
80+
except (yaml.parser.ParserError, yaml.scanner.ScannerError) as e:
81+
raise ValueError(f"Invalid yaml syntax: {e}")
82+
83+
if not isinstance(install_items, list):
84+
raise ValueError("Root of install.yaml file should be a YAML sequence")
85+
86+
system_packages = []
87+
commands = []
88+
89+
# Combine now calls
90+
now_cache = {
91+
"system_now": [],
92+
"pip_now": [],
93+
"pip3_now": [],
94+
"ppa_now": [],
95+
"snap_now": [],
96+
"gem_now": [],
97+
}
98+
99+
def get_distro_item(item: Mapping, key: str, release_version: str, release_type: str) -> Optional[str]:
100+
if key in item:
101+
value = item[key]
102+
if value is None:
103+
raise ValueError(f"'{key}' is defined, but has no value")
104+
elif len(item) < 3 or "default" not in item:
105+
raise ValueError(f"At least one distro and 'default' should be specified or none in install.yaml")
106+
else:
107+
for version in [release_version, "default"]:
108+
if version in item:
109+
value = item[version][key]
110+
break
111+
112+
return value
113+
114+
for install_item in install_items:
115+
command = None
116+
117+
try:
118+
install_type = install_item["type"] # type: str
119+
install_type = install_type.replace("-", "_") # Need after switching to python impl of tue-get
120+
121+
if install_type == "empty":
122+
return {"system_packages": system_packages, "commands": commands}
123+
124+
elif install_type == "ros":
125+
try:
126+
source = get_distro_item(install_item, "source", ros_release, "ROS")
127+
except ValueError as e:
128+
raise ValueError(f"[{install_type}]: {e.args[0]}")
129+
130+
# Both release and default are allowed to be None
131+
if source is None:
132+
continue
133+
134+
source_type = source["type"]
135+
if source_type == "git":
136+
command = partial(getattr(installer, "tue_install_ros"), source_type="git", **catkin_git(source))
137+
elif source_type == "system":
138+
system_packages.append(f"ros-{ros_release}-{source['name']}")
139+
command = partial(getattr(installer, "tue_install_ros"), source_type="system", **catkin_git(source))
140+
else:
141+
raise ValueError(f"Unknown ROS install type: '{source_type}'")
142+
143+
# Non ros targets that are packaged to be built with catkin
144+
elif install_type == "catkin":
145+
source = install_item["source"]
146+
147+
if not source["type"] == "git":
148+
raise ValueError(f"Unknown catkin install type: '{source['type']}'")
149+
command = partial(getattr(installer, "tue_install_ros"), source_type="git", **catkin_git(source))
150+
151+
elif install_type == "git":
152+
command = partial(getattr(installer, "tue_install_git"), source_type="git", **type_git(install_item))
153+
154+
elif install_type in [
155+
"target",
156+
"system",
157+
"pip",
158+
"pip3",
159+
"ppa",
160+
"snap",
161+
"gem",
162+
"dpkg",
163+
"target_now",
164+
"system_now",
165+
"pip_now",
166+
"pip3_now",
167+
"ppa_now",
168+
"snap_now",
169+
"gem_now",
170+
]:
171+
if now and "now" not in install_type:
172+
install_type += "_now"
173+
174+
try:
175+
pkg_name = get_distro_item(install_item, "name", ubuntu_release, "Ubuntu")
176+
except ValueError as e:
177+
raise ValueError(f"[{install_type}]: {e.args[0]}")
178+
179+
# Both release and default are allowed to be None
180+
if pkg_name is None:
181+
continue
182+
183+
if "system" in install_type:
184+
system_packages.append(pkg_name)
185+
186+
# Cache install types which accept multiple pkgs at once
187+
if install_type in now_cache:
188+
now_cache[install_type].append(pkg_name)
189+
continue
190+
command = partial(getattr(installer, f"tue_install_{install_type}"), pkg_name)
191+
192+
else:
193+
raise ValueError(f"Unknown install type: '{install_type}'")
194+
195+
except KeyError as e:
196+
raise KeyError(f"Invalid install.yaml file: Key '{e}' could not be found.")
197+
198+
if not command:
199+
raise ValueError("Invalid install.yaml file")
200+
201+
commands.append(command)
202+
203+
for install_type, pkg_list in now_cache.items():
204+
if pkg_list:
205+
command = partial(getattr(installer, f"tue_install_{install_type}"), pkg_list)
206+
commands.append(command)
207+
208+
return {"system_packages": system_packages, "commands": commands}
209+
210+
211+
if __name__ == "__main__":
212+
import sys
213+
from tue_get.installer_impl import InstallerImpl
214+
if len(sys.argv) < 2:
215+
print("Provide yaml file to parse")
216+
exit(1)
217+
218+
impl = InstallerImpl(True)
219+
print(installyaml_parser(impl, sys.argv[1], False))

0 commit comments

Comments
 (0)