Mercurial > repos > bcclaywell > argo_navis
comparison venv/lib/python2.7/site-packages/planemo/shed_lint.py @ 0:d67268158946 draft
planemo upload commit a3f181f5f126803c654b3a66dd4e83a48f7e203b
author | bcclaywell |
---|---|
date | Mon, 12 Oct 2015 17:43:33 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d67268158946 |
---|---|
1 import os | |
2 import yaml | |
3 from galaxy.tools.lint import LintContext | |
4 from galaxy.tools.linters.help import rst_invalid | |
5 from planemo.lint import lint_xsd | |
6 from planemo.shed import ( | |
7 REPO_TYPE_UNRESTRICTED, | |
8 REPO_TYPE_TOOL_DEP, | |
9 REPO_TYPE_SUITE, | |
10 CURRENT_CATEGORIES, | |
11 validate_repo_owner, | |
12 validate_repo_name, | |
13 ) | |
14 from planemo.tool_lint import ( | |
15 build_lint_args, | |
16 yield_tool_xmls, | |
17 handle_tool_load_error, | |
18 ) | |
19 from planemo.shed2tap import base | |
20 from planemo.xml import XSDS_PATH | |
21 | |
22 | |
23 from planemo.io import info | |
24 from planemo.io import error | |
25 | |
26 from galaxy.tools.lint import lint_xml_with | |
27 | |
28 TOOL_DEPENDENCIES_XSD = os.path.join(XSDS_PATH, "tool_dependencies.xsd") | |
29 REPO_DEPENDENCIES_XSD = os.path.join(XSDS_PATH, "repository_dependencies.xsd") | |
30 | |
31 | |
32 VALID_REPOSITORY_TYPES = [ | |
33 REPO_TYPE_UNRESTRICTED, | |
34 REPO_TYPE_TOOL_DEP, | |
35 REPO_TYPE_SUITE, | |
36 ] | |
37 | |
38 SHED_METADATA = [ | |
39 "description", | |
40 "long_description", | |
41 "remote_repository_url", | |
42 "homepage_url", | |
43 "categories", | |
44 ] | |
45 | |
46 | |
47 def lint_repository(ctx, realized_repository, **kwds): | |
48 # TODO: this really needs to start working with realized path. | |
49 failed = False | |
50 path = realized_repository.real_path | |
51 info("Linting repository %s" % path) | |
52 lint_args = build_lint_args(ctx, **kwds) | |
53 lint_ctx = LintContext(lint_args["level"]) | |
54 lint_ctx.lint( | |
55 "lint_expansion", | |
56 lint_expansion, | |
57 realized_repository, | |
58 ) | |
59 lint_ctx.lint( | |
60 "lint_expected_files", | |
61 lint_expected_files, | |
62 realized_repository, | |
63 ) | |
64 lint_ctx.lint( | |
65 "lint_tool_dependencies_xsd", | |
66 lint_tool_dependencies_xsd, | |
67 path, | |
68 ) | |
69 lint_ctx.lint( | |
70 "lint_tool_dependencies_actions", | |
71 lint_tool_dependencies_actions, | |
72 path, | |
73 ) | |
74 lint_ctx.lint( | |
75 "lint_repository_dependencies", | |
76 lint_repository_dependencies, | |
77 path, | |
78 ) | |
79 lint_ctx.lint( | |
80 "lint_shed_yaml", | |
81 lint_shed_yaml, | |
82 realized_repository, | |
83 ) | |
84 lint_ctx.lint( | |
85 "lint_readme", | |
86 lint_readme, | |
87 path, | |
88 ) | |
89 if kwds["tools"]: | |
90 for (tool_path, tool_xml) in yield_tool_xmls(ctx, path, | |
91 recursive=True): | |
92 info("+Linting tool %s" % tool_path) | |
93 if handle_tool_load_error(tool_path, tool_xml): | |
94 failed = True | |
95 continue | |
96 lint_xml_with( | |
97 lint_ctx, | |
98 tool_xml, | |
99 extra_modules=lint_args["extra_modules"] | |
100 ) | |
101 if kwds["ensure_metadata"]: | |
102 lint_ctx.lint( | |
103 "lint_shed_metadata", | |
104 lint_shed_metadata, | |
105 realized_repository, | |
106 ) | |
107 if not failed: | |
108 failed = lint_ctx.failed(lint_args["fail_level"]) | |
109 if failed: | |
110 error("Failed linting") | |
111 return 1 if failed else 0 | |
112 | |
113 | |
114 def lint_expansion(realized_repository, lint_ctx): | |
115 missing = realized_repository.missing | |
116 if missing: | |
117 msg = "Failed to expand inclusions %s" % missing | |
118 lint_ctx.warn(msg) | |
119 else: | |
120 lint_ctx.info("Included files all found.") | |
121 | |
122 | |
123 def lint_shed_metadata(realized_repository, lint_ctx): | |
124 found_all = True | |
125 for key in SHED_METADATA: | |
126 if key not in realized_repository.config: | |
127 found_all = False | |
128 lint_ctx.warn( | |
129 "Missing shed metadata field [%s] for repository" % key | |
130 ) | |
131 if found_all: | |
132 lint_ctx.info( | |
133 "Found all shed metadata fields required for automated repository " | |
134 "creation and/or updates." | |
135 ) | |
136 | |
137 | |
138 def lint_readme(path, lint_ctx): | |
139 readme_rst = os.path.join(path, "README.rst") | |
140 readme = os.path.join(path, "README") | |
141 readme_txt = os.path.join(path, "README.txt") | |
142 | |
143 readme_found = False | |
144 for readme in [readme_rst, readme, readme_txt]: | |
145 if os.path.exists(readme): | |
146 readme_found = readme | |
147 | |
148 readme_md = os.path.join(path, "README.md") | |
149 if not readme_found and os.path.exists(readme_md): | |
150 lint_ctx.warn("Tool Shed doesn't render markdown, " | |
151 "README.md is invalid readme.") | |
152 return | |
153 | |
154 if not readme_found: | |
155 # TODO: filter on TYPE and make this a warning if | |
156 # unrestricted repository - need to update iuc standards | |
157 # first though. | |
158 lint_ctx.info("No README found skipping.") | |
159 return | |
160 | |
161 if readme_found.endswith(".rst"): | |
162 readme_text = open(readme_found, "r").read() | |
163 invalid_rst = rst_invalid(readme_text) | |
164 if invalid_rst: | |
165 template = "Invalid restructured text found in README [%s]." | |
166 msg = template % invalid_rst | |
167 lint_ctx.warn(msg) | |
168 return | |
169 lint_ctx.info("README found containing valid reStructuredText.") | |
170 else: | |
171 lint_ctx.info("README found containing plain text.") | |
172 | |
173 | |
174 def lint_tool_dependencies_xsd(path, lint_ctx): | |
175 tool_dependencies = os.path.join(path, "tool_dependencies.xml") | |
176 if not os.path.exists(tool_dependencies): | |
177 lint_ctx.info("No tool_dependencies.xml, skipping.") | |
178 return | |
179 lint_xsd(lint_ctx, TOOL_DEPENDENCIES_XSD, tool_dependencies) | |
180 | |
181 | |
182 def lint_tool_dependencies_actions(path, lint_ctx): | |
183 tool_dependencies = os.path.join(path, "tool_dependencies.xml") | |
184 if not os.path.exists(tool_dependencies): | |
185 lint_ctx.info("No tool_dependencies.xml, skipping.") | |
186 return | |
187 try: | |
188 base.Dependencies(tool_dependencies) | |
189 lint_ctx.info("Parsed tool dependencies.") | |
190 except Exception as e: | |
191 import sys | |
192 import traceback | |
193 exc_type, exc_value, exc_traceback = sys.exc_info() | |
194 traceback.print_tb(exc_traceback, limit=1, file=sys.stdout) | |
195 traceback.print_exc() | |
196 template = "Problem parsing tool_dependenies.xml [%s]" | |
197 msg = template % str(e) | |
198 lint_ctx.warn(msg) | |
199 return | |
200 | |
201 | |
202 def lint_expected_files(realized_repository, lint_ctx): | |
203 if realized_repository.is_package: | |
204 if not os.path.exists(realized_repository.tool_dependencies_path): | |
205 lint_ctx.warn("Package repository does not contain a " | |
206 "tool_dependencies.xml file.") | |
207 | |
208 if realized_repository.is_suite: | |
209 if not os.path.exists(realized_repository.repo_dependencies_path): | |
210 lint_ctx.warn("Suite repository does not contain a " | |
211 "repository_dependencies.xml file.") | |
212 | |
213 | |
214 def lint_repository_dependencies(path, lint_ctx): | |
215 repo_dependencies = os.path.join(path, "repository_dependencies.xml") | |
216 if not os.path.exists(repo_dependencies): | |
217 lint_ctx.info("No repository_dependencies.xml, skipping.") | |
218 return | |
219 lint_xsd(lint_ctx, REPO_DEPENDENCIES_XSD, repo_dependencies) | |
220 | |
221 | |
222 def lint_shed_yaml(realized_repository, lint_ctx): | |
223 path = realized_repository.real_path | |
224 shed_yaml = os.path.join(path, ".shed.yml") | |
225 if not os.path.exists(shed_yaml): | |
226 lint_ctx.info("No .shed.yml file found, skipping.") | |
227 return | |
228 try: | |
229 yaml.load(open(shed_yaml, "r")) | |
230 except Exception as e: | |
231 lint_ctx.warn("Failed to parse .shed.yml file [%s]" % str(e)) | |
232 return | |
233 lint_ctx.info(".shed.yml found and appears to be valid YAML.") | |
234 _lint_shed_contents(lint_ctx, realized_repository) | |
235 | |
236 | |
237 def _lint_shed_contents(lint_ctx, realized_repository): | |
238 config = realized_repository.config | |
239 | |
240 def _lint_if_present(key, func, *args): | |
241 value = config.get(key, None) | |
242 if value is not None: | |
243 msg = func(value, *args) | |
244 if msg: | |
245 lint_ctx.warn(msg) | |
246 | |
247 _lint_if_present("owner", validate_repo_owner) | |
248 _lint_if_present("name", validate_repo_name) | |
249 _lint_if_present("type", _validate_repo_type, config["name"]) | |
250 _lint_if_present("categories", _validate_categories, realized_repository) | |
251 | |
252 | |
253 def _validate_repo_type(repo_type, name): | |
254 if repo_type not in VALID_REPOSITORY_TYPES: | |
255 return "Invalid repository type specified [%s]" % repo_type | |
256 | |
257 is_dep = repo_type == "tool_dependency_definition" | |
258 is_suite = repo_type == "repository_suite_definition" | |
259 if is_dep and not name.startswith("package_"): | |
260 return ("Tool dependency definition repositories should have names " | |
261 "starting with package_") | |
262 if is_suite and not name.startswith("suite_"): | |
263 return ("Repository suite definition repositories should have names " | |
264 "starting with suite_") | |
265 if name.startswith("package_") or name.startswith("suite_"): | |
266 if repo_type == "unrestricted": | |
267 return ("Repository name indicated specialized repository type " | |
268 "but repository is listed as unrestricted.") | |
269 | |
270 | |
271 def _validate_categories(categories, realized_repository): | |
272 msg = None | |
273 if len(categories) == 0: | |
274 msg = "Repository should specify one or more categories." | |
275 else: | |
276 for category in categories: | |
277 unknown_categories = [] | |
278 if category not in CURRENT_CATEGORIES: | |
279 unknown_categories.append(category) | |
280 if unknown_categories: | |
281 msg = "Categories [%s] unknown." % unknown_categories | |
282 if realized_repository.is_package: | |
283 if "Tool Dependency Packages" not in categories: | |
284 msg = ("Packages should be placed and should only be placed " | |
285 "in the category 'Tool Dependency Packages'.") | |
286 | |
287 return msg |