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