Skip to content

Commit e2f847a

Browse files
Add tesseract installer script to pull release debians and install (#1113)
1 parent dab52ca commit e2f847a

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

tesseract_installer.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#!/usr/bin/env python3
2+
3+
# Testing locally
4+
# docker run -it -v ~/catkin_ws:/home/catkin_ws --env DEBIAN_FRONTEND=noninteractive ubuntu:jammy bash
5+
# apt update && apt install -y python3 python3-pip curl unzip sudo
6+
# pip3 install requests
7+
# apt install -y --no-install-recommends software-properties-common
8+
# add-apt-repository -y ppa:levi-armstrong/tesseract-robotics
9+
# apt update && apt install -y libompl-dev taskflow
10+
# python3 tesseract_installer.py 0.28 jammy
11+
# export TESSERACT_RESOURCE_PATH=/usr/share/tesseract_support:/usr/share/tesseract_task_composer
12+
13+
import requests
14+
import os
15+
import subprocess
16+
import argparse
17+
18+
# List of GitHub API URLs for the upstream repositories
19+
UPSTREAM_DEPENDS_URLS = [
20+
"https://api.github.com/repos/ros-industrial/ros_industrial_cmake_boilerplate/releases/tags/0.7.2",
21+
"https://api.github.com/repos/ethz-adrl/ifopt/releases/tags/2.1.4",
22+
"https://api.github.com/repos/Jmeyer1292/opw_kinematics/releases/tags/0.5.2",
23+
"https://api.github.com/repos/swri-robotics/descartes_light/releases/tags/0.4.6",
24+
]
25+
26+
# List of GitHub API URLs for the repositories
27+
REPO_API_URLS = [
28+
"https://api.github.com/repos/tesseract-robotics/tesseract/releases",
29+
"https://api.github.com/repos/tesseract-robotics/trajopt/releases",
30+
"https://api.github.com/repos/tesseract-robotics/tesseract_planning/releases",
31+
"https://api.github.com/repos/tesseract-robotics/tesseract_qt/releases",
32+
]
33+
34+
TOKEN = os.getenv("GITHUB_TOKEN") # Optional: GitHub personal access token
35+
36+
def fetch_latest_patch(tag_version_prefix, api_url, token=None):
37+
headers = {"Authorization": f"token {token}"} if token else {}
38+
response = requests.get(api_url, headers=headers)
39+
response.raise_for_status()
40+
releases = response.json()
41+
# Find the latest release matching the tag prefix
42+
for release in releases:
43+
if release["tag_name"].startswith(tag_version_prefix):
44+
return release
45+
raise ValueError(f"No release found for prefix {tag_version_prefix} in {api_url}")
46+
47+
48+
def fetch_assets(release):
49+
return release.get("assets", [])
50+
51+
52+
def download_file(url, output_path):
53+
response = requests.get(url, stream=True)
54+
response.raise_for_status()
55+
with open(output_path, "wb") as f:
56+
for chunk in response.iter_content(chunk_size=8192):
57+
f.write(chunk)
58+
59+
60+
def install_debs_from_zip(zip_file):
61+
print(f"Extracting {zip_file}...")
62+
subprocess.run(["unzip", "-o", zip_file], check=True)
63+
64+
print(f"Installing all .deb files from {zip_file}...")
65+
deb_files = [file for file in os.listdir() if file.endswith(".deb")]
66+
if deb_files:
67+
try:
68+
# Step 1: Attempt to install all .deb files
69+
print(f"Running dpkg to install the following .deb files: {deb_files}")
70+
subprocess.run(["sudo", "dpkg", "-i"] + deb_files, check=True)
71+
except subprocess.CalledProcessError:
72+
print("dpkg encountered dependency issues. Attempting to resolve...")
73+
74+
# Step 2: Resolve dependencies
75+
print("Resolving missing dependencies with apt-get -f install...")
76+
subprocess.run(["sudo", "env", "DEBIAN_FRONTEND=noninteractive", "apt", "-f", "install", "-y"], check=True)
77+
78+
# Step 3: Reconfigure packages to ensure all are configured
79+
print("Reconfiguring packages to complete the installation...")
80+
subprocess.run(["sudo", "dpkg", "--configure", "-a"], check=True)
81+
82+
# Clean up .deb files
83+
for file in deb_files:
84+
os.remove(file)
85+
else:
86+
print(f"No .deb files found in {zip_file}.")
87+
88+
os.remove(zip_file)
89+
90+
91+
def main(tag_version_prefix, distro_name):
92+
93+
for api_url in UPSTREAM_DEPENDS_URLS:
94+
print(f"Processing repository: {api_url}")
95+
try:
96+
# Get the release
97+
headers = {"Authorization": f"token {TOKEN}"} if TOKEN else {}
98+
response = requests.get(api_url, headers=headers)
99+
response.raise_for_status()
100+
release_data = response.json()
101+
102+
# Fetch assest
103+
assets = fetch_assets(release_data)
104+
105+
# Filter assets based on distribution name
106+
filtered_assets = [
107+
asset for asset in assets if f"debian_package_{distro_name}.zip" in asset["name"]
108+
]
109+
110+
if not filtered_assets:
111+
print(f"No matching assets found for {distro_name} in {api_url}.")
112+
continue
113+
114+
for asset in filtered_assets:
115+
name = asset["name"]
116+
download_url = asset["browser_download_url"]
117+
print(f"Downloading {name}...")
118+
download_file(download_url, name)
119+
120+
install_debs_from_zip(name)
121+
122+
print(f"Finished processing repository: {api_url}")
123+
except Exception as e:
124+
print(f"Error processing repository {api_url}: {e}")
125+
126+
for api_url in REPO_API_URLS:
127+
print(f"Processing repository: {api_url}")
128+
try:
129+
latest_release = fetch_latest_patch(tag_version_prefix, api_url, TOKEN)
130+
print(f"Latest release found: {latest_release['tag_name']}")
131+
132+
assets = fetch_assets(latest_release)
133+
# Filter assets based on distribution name
134+
filtered_assets = [
135+
asset for asset in assets if f"debian_package_{distro_name}.zip" in asset["name"]
136+
]
137+
138+
if not filtered_assets:
139+
print(f"No matching assets found for {distro_name} in {api_url}.")
140+
continue
141+
142+
for asset in filtered_assets:
143+
name = asset["name"]
144+
download_url = asset["browser_download_url"]
145+
print(f"Downloading {name}...")
146+
download_file(download_url, name)
147+
148+
install_debs_from_zip(name)
149+
150+
print(f"Finished processing repository: {api_url}")
151+
except Exception as e:
152+
print(f"Error processing repository {api_url}: {e}")
153+
154+
print("All repositories processed!")
155+
156+
157+
if __name__ == "__main__":
158+
parser = argparse.ArgumentParser(
159+
description="Download and install Debian artifacts from multiple GitHub releases for a version prefix."
160+
)
161+
parser.add_argument(
162+
"tag_version_prefix",
163+
help="The version prefix (e.g., 0.28) to fetch the latest patch for all repositories.",
164+
)
165+
parser.add_argument(
166+
"distro_name",
167+
choices=["focal", "jammy", "noble"],
168+
help="The distribution name to filter assets (e.g., focal, jammy, noble).",
169+
)
170+
args = parser.parse_args()
171+
172+
main(args.tag_version_prefix, args.distro_name)

0 commit comments

Comments
 (0)