{# TODO: placeholder/pattern thingybobs #}
-
+
{% trans 'This is used in your code and must be a valid C identifier.' %} {% trans 'It must end with the desired font size.' %}
diff --git a/ide/templates/ide/project/settings.html b/ide/templates/ide/project/settings.html
index cfc0be39..eb6e99ea 100644
--- a/ide/templates/ide/project/settings.html
+++ b/ide/templates/ide/project/settings.html
@@ -120,7 +120,7 @@
+ pattern="{{ regexes.sdk_version }}">
{% trans "App version. Takes the format major[.minor], where major and minor are between 0 and 255." %}
@@ -130,7 +130,7 @@
-
+
diff --git a/ide/tests/test_import_archive.py b/ide/tests/test_import_archive.py
index 69fc6d8e..453cbe71 100644
--- a/ide/tests/test_import_archive.py
+++ b/ide/tests/test_import_archive.py
@@ -12,22 +12,24 @@
fake_s3 = FakeS3()
-RESOURCE_SPEC = {
- 'resources': {
- 'media': [{
- 'file': 'images/blah.png',
- 'name': 'IMAGE_BLAH',
- 'type': 'bitmap'
- }]
- }
-}
-
@mock.patch('ide.models.s3file.s3', fake_s3)
class TestImportProject(CloudpebbleTestCase):
def setUp(self):
self.login()
+ @staticmethod
+ def make_resource_spec(name='IMAGE_BLAH'):
+ return {
+ 'resources': {
+ 'media': [{
+ 'file': 'images/blah.png',
+ 'name': name,
+ 'type': 'bitmap'
+ }]
+ }
+ }
+
def test_import_basic_bundle_with_appinfo(self):
""" Check that a minimal bundle imports without error """
bundle = build_bundle({
@@ -97,7 +99,7 @@ def test_import_appinfo_with_resources(self):
bundle = build_bundle({
'src/main.c': '',
'resources/images/blah.png': 'contents!',
- 'appinfo.json': make_appinfo(options=RESOURCE_SPEC)
+ 'appinfo.json': make_appinfo(options=self.make_resource_spec())
})
do_import_archive(self.project_id, bundle)
project = Project.objects.get(pk=self.project_id)
@@ -108,7 +110,7 @@ def test_import_package_with_resources(self):
bundle = build_bundle({
'src/main.c': '',
'resources/images/blah.png': 'contents!',
- 'package.json': make_package(pebble_options=RESOURCE_SPEC)
+ 'package.json': make_package(pebble_options=self.make_resource_spec())
})
do_import_archive(self.project_id, bundle)
project = Project.objects.get(pk=self.project_id)
@@ -151,3 +153,13 @@ def test_throws_if_importing_array_appkeys_without_npm_manifest_support(self):
})
with self.assertRaises(InvalidProjectArchiveException):
do_import_archive(self.project_id, bundle)
+
+ def test_invalid_resource_id(self):
+ bundle = build_bundle({
+ 'src/main.c': '',
+ 'resources/images/blah.png': 'contents!',
+ 'package.json': make_package(pebble_options=self.make_resource_spec("<>"))
+ })
+
+ with self.assertRaises(ValidationError):
+ do_import_archive(self.project_id, bundle)
diff --git a/ide/utils/cloudpebble_test.py b/ide/utils/cloudpebble_test.py
index 50ffcb86..c826f634 100644
--- a/ide/utils/cloudpebble_test.py
+++ b/ide/utils/cloudpebble_test.py
@@ -56,7 +56,7 @@ def make_appinfo(options=None):
},
"sdkVersion": "3",
"shortName": "test",
- "uuid": "666x6666-x66x-66x6-x666-666666666666",
+ "uuid": "123e4567-e89b-42d3-a456-426655440000",
"versionLabel": "1.0",
"watchapp": {
"watchface": False
@@ -92,7 +92,7 @@ def make_package(package_options=None, pebble_options=None, no_pebble=False):
"media": []
},
"sdkVersion": "3",
- "uuid": '666x6666-x66x-66x6-x666-666666666666',
+ "uuid": '123e4567-e89b-42d3-a456-426655440000',
"watchapp": {
"watchface": False
}
diff --git a/ide/utils/regexes.py b/ide/utils/regexes.py
new file mode 100644
index 00000000..f9a91c06
--- /dev/null
+++ b/ide/utils/regexes.py
@@ -0,0 +1,35 @@
+from django.core.validators import RegexValidator
+
+
+class RegexHolder(object):
+ regex_dictionary = {
+ # Match major[.minor], where major and minor are numbers between 0 and 255 with no leading 0s
+ 'sdk_version': r'^(0|[1-9]\d?|1\d{2}|2[0-4]\d|25[0-5])(\.(0|[1-9]\d?|1\d{2}|2[0-4]\d|25[0-5]))?$',
+
+ # Match major.minor.0, where major and minor are numbers between 0 and 255 with no leading 0s
+ 'semver': r'^(0|[1-9]\d?|1\d{2}|2[0-4]\d|25[0-5])\.(0|[1-9]\d?|1\d{2}|2[0-4]\d|25[0-5])\.0$',
+
+ # Match a string of letters and numbers separated with underscores but not starting with a digit
+ 'c_identifier': r'^\w+$',
+
+ # Match a C identifier optionally followed by an [array index]
+ 'c_identifier_with_index': r'^(\w+)(?:\[(\d+)\])?$',
+
+ # Match a UUID4
+ 'uuid': r'^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$',
+
+ # Match a valid resource file name
+ 'resource_file_name': r'^[/a-zA-Z0-9_(). -]+$',
+
+ # Match a valid c/h/js file name
+ 'source_file_name': r'^[/a-zA-Z0-9_.-]+\.(c|h|js)$'
+ }
+
+ def validator(self, key, message):
+ return [RegexValidator(self.regex_dictionary[key], message=message)]
+
+ def __getattr__(self, key):
+ return self.regex_dictionary[key.lower()]
+
+
+regexes = RegexHolder()
diff --git a/ide/utils/version.py b/ide/utils/version.py
index d8b2d0f4..6a97052b 100644
--- a/ide/utils/version.py
+++ b/ide/utils/version.py
@@ -1,10 +1,6 @@
import re
-# Match major[.minor], where major and minor are numbers between 0 and 255 with no leading 0s
-SDK_VERSION_REGEX = r"^(0|[1-9]\d?|1\d{2}|2[0-4]\d|25[0-5])(\.(0|[1-9]\d?|1\d{2}|2[0-4]\d|25[0-5]))?$"
-
-# Match major.minor.0, where major and minor are numbers between 0 and 255 with no leading 0s
-SEMVER_REGEX = r"^(0|[1-9]\d?|1\d{2}|2[0-4]\d|25[0-5])\.(0|[1-9]\d?|1\d{2}|2[0-4]\d|25[0-5])\.0$"
+from ide.utils.regexes import regexes
def parse_sdk_version(version):
@@ -12,7 +8,7 @@ def parse_sdk_version(version):
:param version: should be "major[.minor]"
:return: (major, minor)
"""
- parsed = re.match(SDK_VERSION_REGEX, version)
+ parsed = re.match(regexes.SDK_VERSION, version)
if not parsed:
raise ValueError("Invalid version {}".format(version))
major = parsed.group(1)
@@ -33,7 +29,7 @@ def parse_semver(semver):
:param semver: should be "major.minor.0"
:return: (major, minor)
"""
- parsed = re.match(SEMVER_REGEX, semver)
+ parsed = re.match(regexes.SEMVER, semver)
if not parsed:
raise ValueError("Invalid semver {}".format(semver))
return parsed.group(1), parsed.group(2)
diff --git a/ide/views/project.py b/ide/views/project.py
index 056be268..dd9116ab 100644
--- a/ide/views/project.py
+++ b/ide/views/project.py
@@ -12,7 +12,8 @@
from ide.tasks.git import hooked_commit
from ide.utils import generate_half_uuid
from utils.td_helper import send_td_event
-from ide.utils.version import SDK_VERSION_REGEX
+from ide.utils.regexes import regexes
+
__author__ = 'katharine'
@@ -49,7 +50,8 @@ def view_project(request, project_id):
'token': token,
'phone_shorturl': settings.PHONE_SHORTURL,
'supported_platforms': supported_platforms,
- 'version_regex': SDK_VERSION_REGEX,
+ 'regexes': regexes,
+ 'regexes_json': json.dumps(regexes.regex_dictionary),
'npm_manifest_support_enabled': settings.NPM_MANIFEST_SUPPORT
})