|
1 | 1 | import os |
| 2 | +import re |
2 | 3 | import yaml |
3 | 4 | from galaxy.tools.lint import LintContext |
4 | 5 | from planemo.lint import lint_xsd |
|
17 | 18 | TOOL_DEPENDENCIES_XSD = os.path.join(XSDS_PATH, "tool_dependencies.xsd") |
18 | 19 | REPO_DEPENDENCIES_XSD = os.path.join(XSDS_PATH, "repository_dependencies.xsd") |
19 | 20 |
|
| 21 | +# TODO: sync this with tool shed impl someday |
| 22 | +VALID_REPOSITORYNAME_RE = re.compile("^[a-z0-9\_]+$") |
| 23 | +VALID_PUBLICNAME_RE = re.compile("^[a-z0-9\-]+$") |
| 24 | + |
| 25 | +VALID_REPOSITORY_TYPES = [ |
| 26 | + "unrestricted", |
| 27 | + "tool_dependency_definition", |
| 28 | + "repository_suite_definition", |
| 29 | +] |
| 30 | + |
20 | 31 |
|
21 | 32 | def lint_repository(ctx, path, **kwds): |
22 | 33 | info("Linting repository %s" % path) |
@@ -76,12 +87,60 @@ def lint_shed_yaml(path, lint_ctx): |
76 | 87 | shed_contents = yaml.load(open(shed_yaml, "r")) |
77 | 88 | except Exception as e: |
78 | 89 | lint_ctx.warn("Failed to parse .shed.yml file [%s]" % str(e)) |
| 90 | + lint_ctx.info(".shed.yml found and appears to be valid YAML.") |
| 91 | + _lint_shed_contents(lint_ctx, path, shed_contents) |
| 92 | + |
| 93 | + |
| 94 | +def _lint_shed_contents(lint_ctx, path, shed_contents): |
| 95 | + def _lint_if_present(key, func, *args): |
| 96 | + value = shed_contents.get(key, None) |
| 97 | + if value is not None: |
| 98 | + msg = func(value, *args) |
| 99 | + if msg: |
| 100 | + lint_ctx.warn(msg) |
| 101 | + |
| 102 | + _lint_if_present("owner", _validate_repo_owner) |
| 103 | + _lint_if_present("name", _validate_repo_name) |
| 104 | + effective_name = shed_contents.get("name", None) or os.path.basename(path) |
| 105 | + _lint_if_present("type", _validate_repo_type, effective_name) |
| 106 | + |
| 107 | + |
| 108 | +def _validate_repo_type(repo_type, name): |
| 109 | + if repo_type not in VALID_REPOSITORY_TYPES: |
| 110 | + return "Invalid repository type specified [%s]" % repo_type |
| 111 | + |
| 112 | + is_dep = repo_type == "tool_dependency_definition" |
| 113 | + is_suite = repo_type == "repository_suite_definition" |
| 114 | + if is_dep and not name.startswith("package_"): |
| 115 | + return ("Tool dependency definition repositories should have names " |
| 116 | + "starting with package_") |
| 117 | + if is_suite and not name.startswith("suite_"): |
| 118 | + return ("Repository suite definition repositories should have names " |
| 119 | + "starting with suite_") |
| 120 | + if name.startswith("package_") or name.startswith("suite_"): |
| 121 | + if repo_type == "unrestricted": |
| 122 | + return ("Repository name indicated specialized repository type " |
| 123 | + "but repository is listed as unrestricted.") |
| 124 | + |
| 125 | + |
| 126 | +def _validate_repo_name(name): |
| 127 | + msg = None |
| 128 | + if len(name) < 2: |
| 129 | + msg = "Repository names must be at least 2 characters in length." |
| 130 | + if len(name) > 80: |
| 131 | + msg = "Repository names cannot be more than 80 characters in length." |
| 132 | + if not(VALID_REPOSITORYNAME_RE.match(name)): |
| 133 | + msg = ("Repository names must contain only lower-case letters, " |
| 134 | + "numbers and underscore.") |
| 135 | + return msg |
79 | 136 |
|
80 | | - warned = False |
81 | | - for required_key in ["owner", "name"]: |
82 | | - if required_key not in shed_contents: |
83 | | - lint_ctx.warn(".shed.yml did not contain key [%s]" % required_key) |
84 | | - warned = True |
85 | 137 |
|
86 | | - if not warned: |
87 | | - lint_ctx.info(".shed.yml found and appears to be valid YAML.") |
| 138 | +def _validate_repo_owner(owner): |
| 139 | + msg = None |
| 140 | + if len(owner) < 3: |
| 141 | + msg = "Owner must be at least 3 characters in length" |
| 142 | + if len(owner) > 255: |
| 143 | + msg = "Owner cannot be more than 255 characters in length" |
| 144 | + if not(VALID_PUBLICNAME_RE.match(owner)): |
| 145 | + msg = "Owner must contain only lower-case letters, numbers and '-'" |
| 146 | + return msg |
0 commit comments