comparison env/lib/python3.7/site-packages/planemo/conda_lint.py @ 0:26e78fe6e8c4 draft

"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author shellac
date Sat, 02 May 2020 07:14:21 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:26e78fe6e8c4
1 """Logic for linting conda recipes."""
2
3 from __future__ import absolute_import
4
5 from functools import wraps
6
7 from galaxy.tool_util.deps.conda_compat import raw_metadata
8 from galaxy.util import unicodify
9
10 from planemo.conda_verify.recipe import (
11 check_build_number,
12 check_dir_content,
13 check_license_family,
14 check_name,
15 check_requirements,
16 check_source,
17 check_url,
18 check_version,
19 FIELDS,
20 get_field,
21 RecipeError,
22 )
23 from planemo.exit_codes import (
24 EXIT_CODE_GENERIC_FAILURE,
25 EXIT_CODE_OK,
26 )
27 from planemo.io import (
28 coalesce_return_codes,
29 find_matching_directories,
30 info,
31 )
32 from planemo.lint import (
33 handle_lint_complete,
34 setup_lint,
35 )
36
37
38 def lint_recipes_on_paths(ctx, paths, **kwds):
39 """Apply conda linting procedure to recipes on supplied paths."""
40 assert_tools = kwds.get("assert_recipes", True)
41 recursive = kwds.get("recursive", False)
42 exit_codes = []
43 for recipe_dir in yield_recipes_on_paths(ctx, paths, recursive):
44 if lint_conda_recipe(ctx, recipe_dir, **kwds) != 0:
45 exit_codes.append(EXIT_CODE_GENERIC_FAILURE)
46 else:
47 exit_codes.append(EXIT_CODE_OK)
48 return coalesce_return_codes(exit_codes, assert_at_least_one=assert_tools)
49
50
51 def lint_conda_recipe(ctx, recipe_dir, **kwds):
52 info("Linting conda recipe %s" % recipe_dir)
53 lint_args, lint_ctx = setup_lint(ctx, **kwds)
54
55 def apply(f):
56 lint_ctx.lint(f.__name__, f, recipe_dir)
57
58 apply(lint_name)
59 apply(lint_version)
60 apply(lint_summary)
61 apply(lint_build_number)
62 apply(lint_directory_content)
63 apply(lint_license_family)
64 apply(lint_about_urls)
65 apply(lint_source)
66 apply(lint_fields)
67 apply(lint_requirements)
68
69 return handle_lint_complete(lint_ctx, lint_args)
70
71
72 def wraps_recipe_error(is_error=True):
73
74 def outer_wrapper(f):
75
76 @wraps(f)
77 def wrapper(recipe_dir, lint_ctx):
78 try:
79 f(recipe_dir, lint_ctx)
80 except RecipeError as e:
81 if is_error:
82 lint_ctx.error(unicodify(e))
83 else:
84 lint_ctx.warn(unicodify(e))
85 except TypeError as e: # Errors in recipe checking code from YAML.
86 lint_ctx.error(unicodify(e))
87
88 return wrapper
89
90 return outer_wrapper
91
92
93 def lints_metadata(f):
94
95 @wraps(f)
96 def wrapper(recipe_dir, lint_ctx):
97 meta = raw_metadata(recipe_dir)
98 f(meta, lint_ctx)
99
100 return wrapper
101
102
103 @wraps_recipe_error(is_error=False)
104 def lint_directory_content(recipe_dir, lint_ctx):
105 check_dir_content(recipe_dir)
106 lint_ctx.info("Directory content seems okay.")
107
108
109 @lints_metadata
110 @wraps_recipe_error(is_error=False)
111 def lint_license_family(meta, lint_ctx):
112 check_license_family(meta)
113 lint_ctx.info("License from vaild license family.")
114
115
116 @lints_metadata
117 def lint_summary(meta, lint_ctx):
118 summary = get_field(meta, 'about/summary')
119
120 if not summary:
121 lint_ctx.warn("No summary supplied in about metadata.")
122
123 if summary and len(summary) > 80:
124 msg = "summary exceeds 80 characters"
125 lint_ctx.warn(msg)
126
127
128 @lints_metadata
129 @wraps_recipe_error(is_error=False)
130 def lint_about_urls(meta, lint_ctx):
131 for field in ('about/home', 'about/dev_url', 'about/doc_url',
132 'about/license_url'):
133 url = get_field(meta, field)
134 if url:
135 check_url(url)
136 lint_ctx.info("About urls (if present) are valid")
137
138
139 @lints_metadata
140 @wraps_recipe_error(is_error=True)
141 def lint_source(meta, lint_ctx):
142 check_source(meta)
143 lint_ctx.info("Source (if present) is valid")
144
145
146 @lints_metadata
147 @wraps_recipe_error(is_error=True)
148 def lint_build_number(meta, lint_ctx):
149 build_number = get_field(meta, 'build/number', 0)
150 check_build_number(build_number)
151 lint_ctx.info("Valid build number [%s]" % build_number)
152
153
154 @lints_metadata
155 @wraps_recipe_error(is_error=True)
156 def lint_version(meta, lint_ctx):
157 version = get_field(meta, 'package/version')
158 check_version(version)
159 lint_ctx.info("Valid version number [%s]" % version)
160
161
162 @lints_metadata
163 @wraps_recipe_error(is_error=True)
164 def lint_name(meta, lint_ctx):
165 name = get_field(meta, 'package/name')
166 check_name(name)
167 lint_ctx.info("Valid recipe name [%s]" % name)
168
169
170 @lints_metadata
171 @wraps_recipe_error(is_error=False)
172 def lint_fields(meta, lint_ctx):
173 # Taken from validate_meta
174 for section in meta:
175 if section not in FIELDS:
176 raise RecipeError("Unknown section: %s" % section)
177 submeta = meta.get(section)
178 if submeta is None:
179 submeta = {}
180 for key in submeta:
181 # Next two lines added for planemo since we don't do the
182 # select lines thing.
183 if key == "skip":
184 continue
185
186 if key not in FIELDS[section]:
187 raise RecipeError("in section %r: unknown key %r" %
188 (section, key))
189
190
191 @lints_metadata
192 @wraps_recipe_error(is_error=False)
193 def lint_requirements(meta, lint_ctx):
194 check_requirements(meta)
195 lint_ctx.info("Reference recipe files appear valid")
196
197
198 def yield_recipes_on_paths(ctx, paths, recursive):
199 for path in paths:
200 recipe_dirs = find_matching_directories(
201 path, "meta.yaml", recursive=recursive
202 )
203 for recipe_dir in recipe_dirs:
204 yield recipe_dir
205
206
207 __all__ = (
208 "lint_recipes_on_paths",
209 )