|
3 | 3 | import hashlib |
4 | 4 | import json |
5 | 5 | import os |
| 6 | +import re |
6 | 7 | import tarfile |
7 | 8 | from tempfile import ( |
8 | 9 | mkstemp, |
|
66 | 67 | REPO_TYPE_TOOL_DEP = "tool_dependency_definition" |
67 | 68 | REPO_TYPE_SUITE = "repository_suite_definition" |
68 | 69 |
|
| 70 | +# TODO: sync this with tool shed impl someday |
| 71 | +VALID_REPOSITORYNAME_RE = re.compile("^[a-z0-9\_]+$") |
| 72 | +VALID_PUBLICNAME_RE = re.compile("^[a-z0-9\-]+$") |
| 73 | + |
69 | 74 | # Generate with python scripts/categories.py |
70 | 75 | CURRENT_CATEGORIES = [ |
71 | 76 | "Assembly", |
@@ -111,7 +116,10 @@ def shed_init(ctx, path, **kwds): |
111 | 116 | # .shed.yml exists and no --force sent. |
112 | 117 | return 1 |
113 | 118 |
|
114 | | - _create_shed_config(ctx, shed_config_path, **kwds) |
| 119 | + create_failed = _create_shed_config(ctx, shed_config_path, **kwds) |
| 120 | + if create_failed: |
| 121 | + return 1 |
| 122 | + |
115 | 123 | repo_dependencies_path = os.path.join(path, REPO_DEPENDENCIES_CONFIG_NAME) |
116 | 124 | from_workflow = kwds.get("from_workflow", None) |
117 | 125 |
|
@@ -427,9 +435,18 @@ def realize_effective_repositories(path, **kwds): |
427 | 435 |
|
428 | 436 | def _create_shed_config(ctx, path, **kwds): |
429 | 437 | name = kwds.get("name", None) or path_to_repo_name(os.path.dirname(path)) |
| 438 | + name_invalid = validate_repo_name(name) |
| 439 | + if name_invalid: |
| 440 | + error(name_invalid) |
| 441 | + return 1 |
| 442 | + |
430 | 443 | owner = kwds.get("owner", None) |
431 | 444 | if owner is None: |
432 | 445 | owner = ctx.global_config.get("shed_username", None) |
| 446 | + owner_invalid = validate_repo_owner(owner) |
| 447 | + if owner_invalid: |
| 448 | + error(owner_invalid) |
| 449 | + return 1 |
433 | 450 | description = kwds.get("description", None) or name |
434 | 451 | long_description = kwds.get("long_description", None) |
435 | 452 | remote_repository_url = kwds.get("remote_repository_url", None) |
@@ -768,6 +785,45 @@ def _glob(path, pattern): |
768 | 785 | def _shed_config_excludes(config): |
769 | 786 | return config.get('ignore', []) + config.get('exclude', []) |
770 | 787 |
|
| 788 | + |
| 789 | +def validate_repo_name(name): |
| 790 | + def _build_error(descript): |
| 791 | + return "Repository name [%s] invalid. %s" % (name, descript) |
| 792 | + |
| 793 | + msg = None |
| 794 | + if len(name) < 2: |
| 795 | + msg = _build_error( |
| 796 | + "Repository names must be at least 2 characters in length." |
| 797 | + ) |
| 798 | + if len(name) > 80: |
| 799 | + msg = _build_error( |
| 800 | + "Repository names cannot be more than 80 characters in length." |
| 801 | + ) |
| 802 | + if not VALID_REPOSITORYNAME_RE.match(name): |
| 803 | + msg = _build_error( |
| 804 | + "Repository names must contain only lower-case letters, " |
| 805 | + "numbers and underscore." |
| 806 | + ) |
| 807 | + return msg |
| 808 | + |
| 809 | + |
| 810 | +def validate_repo_owner(owner): |
| 811 | + def _build_error(descript): |
| 812 | + return "Owner [%s] invalid. %s" % (owner, descript) |
| 813 | + msg = None |
| 814 | + if len(owner) < 3: |
| 815 | + msg = _build_error("Owner must be at least 3 characters in length") |
| 816 | + if len(owner) > 255: |
| 817 | + msg = _build_error( |
| 818 | + "Owner cannot be more than 255 characters in length" |
| 819 | + ) |
| 820 | + if not(VALID_PUBLICNAME_RE.match(owner)): |
| 821 | + msg = _build_error( |
| 822 | + "Owner must contain only lower-case letters, numbers and '-'" |
| 823 | + ) |
| 824 | + return msg |
| 825 | + |
| 826 | + |
771 | 827 | __all__ = [ |
772 | 828 | 'for_each_repository', |
773 | 829 | 'api_exception_to_message', |
|
0 commit comments