Skip to content

Commit

Permalink
Improved shed linting and type default.
Browse files Browse the repository at this point in the history
No .shed.yml fields are required anymore, but when present more are validated more carefully.

 - Validate owner string matches validation inforced by Tool Shed.
 - Validate name string matches validation inforced by Tool Shed.
 - Validate type (if specified) is valid.
 - Validate name matches type conventions.

Use new validation to more confidently select a default type based on name during creation.
  • Loading branch information
jmchilton committed Apr 22, 2015
1 parent 1346ba0 commit 36ac6d8
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 8 deletions.
9 changes: 8 additions & 1 deletion planemo/shed.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def create_repository(ctx, tsi, path, **kwds):

description = repo_config.get("description", None)
long_description = repo_config.get("long_description", None)
type = repo_config.get("type", "unrestricted")
type = repo_config.get("type", None)
remote_repository_url = repo_config.get("remote_repository_url", None)
homepage_url = repo_config.get("homepage_url", None)
categories = repo_config.get("categories", [])
Expand All @@ -137,6 +137,13 @@ def create_repository(ctx, tsi, path, **kwds):
if name is None:
name = os.path.basename(os.path.abspath(path))

if type is None and name.startswith("package_"):
type = "tool_dependency_definition"
elif type is None and name.startswith("suite_"):
type = "repository_suite_definition"
elif type is None:
type = "unrestricted"

# description is required, as is name.
if description is None:
message = "description required for automatic creation of repositories"
Expand Down
73 changes: 66 additions & 7 deletions planemo/shed_lint.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import re
import yaml
from galaxy.tools.lint import LintContext
from planemo.lint import lint_xsd
Expand All @@ -17,6 +18,16 @@
TOOL_DEPENDENCIES_XSD = os.path.join(XSDS_PATH, "tool_dependencies.xsd")
REPO_DEPENDENCIES_XSD = os.path.join(XSDS_PATH, "repository_dependencies.xsd")

# TODO: sync this with tool shed impl someday
VALID_REPOSITORYNAME_RE = re.compile("^[a-z0-9\_]+$")
VALID_PUBLICNAME_RE = re.compile("^[a-z0-9\-]+$")

VALID_REPOSITORY_TYPES = [
"unrestricted",
"tool_dependency_definition",
"repository_suite_definition",
]


def lint_repository(ctx, path, **kwds):
info("Linting repository %s" % path)
Expand Down Expand Up @@ -76,12 +87,60 @@ def lint_shed_yaml(path, lint_ctx):
shed_contents = yaml.load(open(shed_yaml, "r"))
except Exception as e:
lint_ctx.warn("Failed to parse .shed.yml file [%s]" % str(e))
lint_ctx.info(".shed.yml found and appears to be valid YAML.")
_lint_shed_contents(lint_ctx, path, shed_contents)


def _lint_shed_contents(lint_ctx, path, shed_contents):
def _lint_if_present(key, func, *args):
value = shed_contents.get(key, None)
if value is not None:
msg = func(value, *args)
if msg:
lint_ctx.warn(msg)

_lint_if_present("owner", _validate_repo_owner)
_lint_if_present("name", _validate_repo_name)
effective_name = shed_contents.get("name", None) or os.path.basename(path)
_lint_if_present("type", _validate_repo_type, effective_name)


def _validate_repo_type(repo_type, name):
if repo_type not in VALID_REPOSITORY_TYPES:
return "Invalid repository type specified [%s]" % repo_type

is_dep = repo_type == "tool_dependency_definition"
is_suite = repo_type == "repository_suite_definition"
if is_dep and not name.startswith("package_"):
return ("Tool dependency definition repositories should have names "
"starting with package_")
if is_suite and not name.startswith("suite_"):
return ("Repository suite definition repositories should have names "
"starting with suite_")
if name.startswith("package_") or name.startswith("suite_"):
if repo_type == "unrestricted":
return ("Repository name indicated specialized repository type "
"but repository is listed as unrestricted.")


def _validate_repo_name(name):
msg = None
if len(name) < 2:
msg = "Repository names must be at least 2 characters in length."
if len(name) > 80:
msg = "Repository names cannot be more than 80 characters in length."
if not(VALID_REPOSITORYNAME_RE.match(name)):
msg = ("Repository names must contain only lower-case letters, "
"numbers and underscore.")
return msg

warned = False
for required_key in ["owner", "name"]:
if required_key not in shed_contents:
lint_ctx.warn(".shed.yml did not contain key [%s]" % required_key)
warned = True

if not warned:
lint_ctx.info(".shed.yml found and appears to be valid YAML.")
def _validate_repo_owner(owner):
msg = None
if len(owner) < 3:
msg = "Owner must be at least 3 characters in length"
if len(owner) > 255:
msg = "Owner cannot be more than 255 characters in length"
if not(VALID_PUBLICNAME_RE.match(owner)):
msg = "Owner must contain only lower-case letters, numbers and '-'"
return msg

0 comments on commit 36ac6d8

Please sign in to comment.