Skip to content

Commit 35486cd

Browse files
add script to remove uninstallable revisions from lock files
1 parent 2a6bd81 commit 35486cd

1 file changed

Lines changed: 127 additions & 0 deletions

File tree

scripts/fix-uninstallable.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# check all revisions in the lockfile if they are installable
2+
# remove if not and the next installable version is installed
3+
#
4+
# backgroud vor each version there can be only one revision installed
5+
# (multiple revisions with the same version happen eg if the version
6+
# is not bumbed)
7+
#
8+
# revisions that became uninstallable can be safely removed since
9+
#
10+
# - tool revision can not be executed anyway
11+
# - also if another instance requests to install then the latest
12+
# revision with the same version will be installed
13+
#
14+
# the script queries the TS to get_ordered_installable_revisions
15+
# and clones (to /tmp/) the mercurial repos to get all revisions
16+
# (the later is opnly done for tools with revisions that are not
17+
# installable)
18+
19+
import argparse
20+
import subprocess
21+
import os.path
22+
import yaml
23+
24+
from bioblend import toolshed
25+
from galaxy.tool_util.loader_directory import load_tool_sources_from_path
26+
27+
28+
def clone(toolshed_url, name, owner, repo_path):
29+
if not os.path.exists(repo_path):
30+
cmd = [
31+
"hg",
32+
"clone",
33+
f"{toolshed_url}/repos/{owner}/{name}",
34+
repo_path,
35+
]
36+
subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
37+
38+
39+
def get_all_revisions(toolshed_url, name, owner):
40+
repo_path = f"/tmp/toolshed-{owner}-{name}"
41+
clone(toolshed_url, name, owner, repo_path)
42+
cmd = ["hg", "update", "tip"]
43+
cmd = ["hg", "log", "--template", "{node|short}\n"]
44+
result = subprocess.run(cmd, cwd=repo_path, capture_output=True, text=True)
45+
return list(reversed(result.stdout.splitlines()))
46+
47+
48+
def get_all_versions(toolshed_url, name, owner, revisions):
49+
repo_path = f"/tmp/toolshed-{owner}-{name}"
50+
clone(toolshed_url, name, owner, repo_path)
51+
52+
versions = {}
53+
for r in revisions:
54+
cmd = ["hg", "update", r]
55+
subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
56+
57+
versions[r] = set()
58+
for _, tool in load_tool_sources_from_path(repo_path):
59+
versions[r].add((tool.parse_id(), tool.parse_version()))
60+
61+
return versions
62+
63+
64+
def fix_uninstallable(lockfile_name, toolshed_url):
65+
ts = toolshed.ToolShedInstance(url=toolshed_url)
66+
67+
with open(lockfile_name) as f:
68+
lockfile = yaml.safe_load(f)
69+
tools = lockfile["tools"]
70+
71+
for i, tool in enumerate(tools):
72+
name = tool["name"]
73+
owner = tool["owner"]
74+
75+
# get ordered_installable_revisions from oldest to newest
76+
ordered_installable_revisions = (
77+
ts.repositories.get_ordered_installable_revisions(name, owner)
78+
)
79+
80+
if len(set(tool["revisions"]) - set(ordered_installable_revisions)):
81+
all_revisions = get_all_revisions(toolshed_url, name, owner)
82+
# all_versions = get_all_versions(toolshed_url, name, owner, all_revisions)
83+
84+
remove = []
85+
for cur in tool["revisions"]:
86+
if cur in ordered_installable_revisions:
87+
continue
88+
if cur not in all_revisions:
89+
print(f"{cur} is not a valid revision of {name} {owner}")
90+
remove.append(cur)
91+
continue
92+
start = all_revisions.index(cur)
93+
nxt = None
94+
for i in range(start, len(all_revisions)):
95+
if all_revisions[i] in ordered_installable_revisions:
96+
nxt = all_revisions[i]
97+
if nxt:
98+
if nxt in tool["revisions"]:
99+
print(f"remove {cur} in favor of {nxt} {name} {owner}")
100+
remove.append(cur)
101+
else:
102+
# not adding, will be done in next update anyway
103+
print(
104+
f"NOT removing {cur} since {nxt} not installed {name} {owner}"
105+
)
106+
else:
107+
print(f"Could not determine next revision for {cur} {name} {owner}")
108+
109+
for r in remove:
110+
tool["revisions"].remove(r)
111+
112+
with open(lockfile_name, "w") as handle:
113+
yaml.dump(lockfile, handle, default_flow_style=False)
114+
115+
116+
if __name__ == "__main__":
117+
parser = argparse.ArgumentParser()
118+
parser.add_argument(
119+
"lockfile", type=argparse.FileType("r"), help="Tool.yaml.lock file"
120+
)
121+
parser.add_argument(
122+
"--toolshed",
123+
default="https://toolshed.g2.bx.psu.edu",
124+
help="Toolshed to test against",
125+
)
126+
args = parser.parse_args()
127+
fix_uninstallable(args.lockfile.name, args.toolshed)

0 commit comments

Comments
 (0)