Skip to content
This repository was archived by the owner on Apr 26, 2026. It is now read-only.

Commit 3944686

Browse files
authored
Update install.py
1 parent b40ddd8 commit 3944686

1 file changed

Lines changed: 159 additions & 148 deletions

File tree

src/install.py

Lines changed: 159 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -12,171 +12,182 @@
1212
# init rich console
1313
console = Console()
1414

15+
# Track packages currently being installed to prevent circular dependencies
16+
_installing = set()
17+
1518
def main(package, noconfirm=False):
1619
# first check if the name is correct, autocorrect if not
1720
# using umbrella/autocorrect_package.py (unlicense)
1821
autocorrected = Autocorrect.main(package)
1922
if autocorrected != package:
2023
package = autocorrected
2124

22-
# save time fetching scripts, check if the package is in lists quickly
23-
if get_package_list.main(package) != True:
24-
return False
25-
26-
# main
25+
# Prevent circular dependencies and infinite loops
26+
if package in _installing:
27+
return
28+
_installing.add(package)
2729
try:
28-
# save installed package
29-
repro_path = "/home/" + os.getlogin() + "/.config/repro.car"
30-
31-
def read_installed_versions(path):
32-
versions = {}
33-
if not os.path.isfile(path):
30+
# save time fetching scripts, check if the package is in lists quickly
31+
if get_package_list.main(package) != True:
32+
return False
33+
34+
# main
35+
try:
36+
# save installed package
37+
repro_path = "/home/" + os.getlogin() + "/.config/repro.car"
38+
39+
def read_installed_versions(path):
40+
versions = {}
41+
if not os.path.isfile(path):
42+
return versions
43+
with open(path, "r") as f:
44+
for line in f.read().splitlines():
45+
if not line.strip():
46+
continue
47+
if "=" in line:
48+
name, ver = line.split("=", 1)
49+
versions[name.strip()] = ver.strip()
50+
else:
51+
versions[line.strip()] = ""
3452
return versions
35-
with open(path, "r") as f:
36-
for line in f.read().splitlines():
37-
if not line.strip():
38-
continue
39-
if "=" in line:
40-
name, ver = line.split("=", 1)
41-
versions[name.strip()] = ver.strip()
53+
54+
def write_installed_versions(path, versions):
55+
lines = []
56+
for name, ver in versions.items():
57+
if ver:
58+
lines.append(f"{name}={ver}")
4259
else:
43-
versions[line.strip()] = ""
44-
return versions
45-
46-
def write_installed_versions(path, versions):
47-
lines = []
48-
for name, ver in versions.items():
49-
if ver:
50-
lines.append(f"{name}={ver}")
51-
else:
52-
lines.append(name)
53-
with open(path, "w") as f:
54-
f.write("\n".join(lines) + "\n")
60+
lines.append(name)
61+
with open(path, "w") as f:
62+
f.write("\n".join(lines) + "\n")
5563

56-
# go to /tmp
57-
os.chdir("/tmp/")
64+
# go to /tmp
65+
os.chdir("/tmp/")
5866

59-
status("Fetching package")
67+
status("Fetching package")
6068

61-
# fetch all repos for the install script
62-
found = False
69+
# fetch all repos for the install script
70+
found = False
6371

64-
for mirror in mirrors.install_script_places:
65-
url = f"{mirror.rstrip('/')}/{package}/install_script"
72+
for mirror in mirrors.install_script_places:
73+
url = f"{mirror.rstrip('/')}/{package}/install_script"
6674

67-
result = os.system(f"curl -s -L -o install_script.py {url}")
75+
result = os.system(f"curl -s -L -o install_script.py {url}")
6876

69-
with open("install_script.py", "r") as f:
70-
script = f.read()
77+
with open("install_script.py", "r") as f:
78+
script = f.read()
7179

72-
# github returns 404: Not Found in case the file does not exist,
73-
# so handle that case too
74-
if script != "404: Not Found":
75-
found = True
76-
break
80+
# github returns 404: Not Found in case the file does not exist,
81+
# so handle that case too
82+
if script != "404: Not Found":
83+
found = True
84+
break
85+
else:
86+
pass
87+
88+
if not found:
89+
status("Failed to fetch install script from all mirrors", "error")
90+
exit(1)
91+
92+
# import the script as a python library
93+
spec = importlib.util.spec_from_file_location("install_script", "/tmp/install_script.py")
94+
install_script = importlib.util.module_from_spec(spec)
95+
spec.loader.exec_module(install_script)
96+
97+
# check for version
98+
script_version = None
99+
if hasattr(install_script, "VERSION"):
100+
script_version = getattr(install_script, "VERSION")
101+
elif hasattr(install_script, "version"):
102+
script_version = getattr(install_script, "version")
103+
if script_version is None:
104+
script_version = ""
77105
else:
78-
pass
79-
80-
if not found:
81-
status("Failed to fetch install script from all mirrors", "error")
82-
exit(1)
83-
84-
# import the script as a python library
85-
spec = importlib.util.spec_from_file_location("install_script", "/tmp/install_script.py")
86-
install_script = importlib.util.module_from_spec(spec)
87-
spec.loader.exec_module(install_script)
88-
89-
# check for version
90-
script_version = None
91-
if hasattr(install_script, "VERSION"):
92-
script_version = getattr(install_script, "VERSION")
93-
elif hasattr(install_script, "version"):
94-
script_version = getattr(install_script, "version")
95-
if script_version is None:
96-
script_version = ""
97-
else:
98-
script_version = script_version
99-
100-
# reinstall if new version available
101-
installed_versions = read_installed_versions(repro_path)
102-
installed_version = installed_versions.get(package)
103-
if installed_version is not None and installed_version == script_version:
104-
status(f"{package} is up to date ({script_version}). Exiting.", "ok")
105-
return
106-
elif installed_version is not None and installed_version != script_version:
107-
status(f"New version available for {package}: {installed_version} -> {script_version}. Reinstalling.", "warn")
108-
elif installed_version is None:
109-
if not os.path.isfile(repro_path):
110-
status("No repro.car file. Creating", "warn")
111-
with open(repro_path, "w") as f:
112-
f.write("")
113-
114-
# beforeinst hook
115-
if hasattr(install_script, "beforeinst"):
116-
install_script.beforeinst()
117-
118-
# ask for confirmation
119-
if not noconfirm:
120-
status("The following packages are going to be installed:")
121-
print(" ", end="")
122-
for i in install_script.car_deps:
123-
print(i, end=", ")
124-
print(package) # appending to the list did not work for some reason
125-
console.print("::", style="blue bold", end=" ")
126-
sure = input("Install dependencies and build? (Y/n) ")
127-
if sure not in ("", "y", "Y"):
128-
return
106+
script_version = script_version
129107

130-
# install deps
131-
if "deps" in script:
132-
try:
133-
install_script.deps()
134-
except Exception:pass
135-
if "car_deps" in script:
136-
for i in install_script.car_deps:
137-
install.main(i, noconfirm=True)
138-
139-
# build
140-
if "build" in script:
141-
try:
142-
install_script.build()
143-
except Exception:pass
144-
145-
# ask for confirmation
146-
# todo: make confirmation prompts better by mixing into one
147-
if not noconfirm:
148-
console.print("::", style="blue bold", end=" ")
149-
sure = input("Install? (Y/n) ")
150-
if sure not in ("", "y", "Y"):
108+
# reinstall if new version available
109+
installed_versions = read_installed_versions(repro_path)
110+
installed_version = installed_versions.get(package)
111+
if installed_version is not None and installed_version == script_version:
112+
status(f"{package} is up to date ({script_version}). Exiting.", "ok")
151113
return
152-
153-
# install, required hook
154-
status("Installing", "ok")
155-
install_script.install()
156-
157-
158-
if not "DoNotWriteVersion = True" in script:
159-
installed_versions[package] = script_version
160-
write_installed_versions(repro_path, installed_versions)
161-
162-
hooks.post_inst(package)
163-
164-
# postinst hook
165-
if hasattr(install_script, "postinst"):
166-
install_script.postinst()
167-
168-
# clean up
169-
os.system("rm -f /tmp/install_script.py")
170-
except Exception:
171-
# crash, print exception and exit
172-
console.print("::", style="red", end=" ")
173-
console.print("Unhandled exception")
174-
console.print_exception()
175-
sys.exit(1)
176-
except KeyboardInterrupt:
177-
# keyboard interrupt, suggest cleaning up
178-
status("Installation interrupted", "error")
179-
status("There might be some files that were installed, but not removed. You can remove them manually.", "warn")
180-
status("If you want to remove them, run the following command:", "warn")
181-
status("sudo car delete " + package, "warn")
182-
sys.exit(1)
114+
elif installed_version is not None and installed_version != script_version:
115+
status(f"New version available for {package}: {installed_version} -> {script_version}. Reinstalling.", "warn")
116+
elif installed_version is None:
117+
if not os.path.isfile(repro_path):
118+
status("No repro.car file. Creating", "warn")
119+
with open(repro_path, "w") as f:
120+
f.write("")
121+
122+
# beforeinst hook
123+
if hasattr(install_script, "beforeinst"):
124+
install_script.beforeinst()
125+
126+
# ask for confirmation
127+
if not noconfirm:
128+
status("The following packages are going to be installed:")
129+
print(" ", end="")
130+
for i in install_script.car_deps:
131+
print(i, end=", ")
132+
print(package) # appending to the list did not work for some reason
133+
console.print("::", style="blue bold", end=" ")
134+
sure = input("Install dependencies and build? (Y/n) ")
135+
if sure not in ("", "y", "Y"):
136+
return
137+
138+
# install deps
139+
if "deps" in script:
140+
try:
141+
install_script.deps()
142+
except Exception:pass
143+
if "car_deps" in script:
144+
for i in install_script.car_deps:
145+
install.main(i, noconfirm=True)
146+
147+
# build
148+
if "build" in script:
149+
try:
150+
install_script.build()
151+
except Exception:pass
152+
153+
# ask for confirmation
154+
# todo: make confirmation prompts better by mixing into one
155+
if not noconfirm:
156+
console.print("::", style="blue bold", end=" ")
157+
sure = input("Install? (Y/n) ")
158+
if sure not in ("", "y", "Y"):
159+
return
160+
161+
# install, required hook
162+
status("Installing", "ok")
163+
install_script.install()
164+
165+
166+
if not "DoNotWriteVersion = True" in script:
167+
installed_versions[package] = script_version
168+
write_installed_versions(repro_path, installed_versions)
169+
170+
hooks.post_inst(package)
171+
172+
# postinst hook
173+
if hasattr(install_script, "postinst"):
174+
install_script.postinst()
175+
176+
# clean up
177+
os.system("sudo rm -f /tmp/install_script.py")
178+
except Exception:
179+
# crash, print exception and exit
180+
console.print("::", style="red", end=" ")
181+
console.print("Unhandled exception")
182+
console.print_exception()
183+
sys.exit(1)
184+
except KeyboardInterrupt:
185+
# keyboard interrupt, suggest cleaning up
186+
status("Installation interrupted", "error")
187+
status("There might be some files that were installed, but not removed. You can remove them manually.", "warn")
188+
status("If you want to remove them, run the following command:", "warn")
189+
status("sudo car delete " + package, "warn")
190+
sys.exit(1)
191+
finally:
192+
# Always remove from installing set, even if installation fails
193+
_installing.discard(package)

0 commit comments

Comments
 (0)