update_36.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #!/usr/bin/env python3
  2. # Contest Management System - http://cms-dev.github.io/
  3. # Copyright © 2018 Luca Wehrstedt <luca.wehrstedt@gmail.com>
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU Affero General Public License as
  6. # published by the Free Software Foundation, either version 3 of the
  7. # License, or (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU Affero General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU Affero General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. """A class to update a dump created by CMS.
  17. Used by DumpImporter and DumpUpdater.
  18. This updater makes sure filenames contain no percent sign, except in a
  19. trailing ".%l", if any.
  20. """
  21. import logging
  22. logger = logging.getLogger(__name__)
  23. # Fields that contain filenames.
  24. FILENAME_FIELDS = {
  25. "Executable": "filename",
  26. "UserTestManager": "filename",
  27. "UserTestExecutable": "filename",
  28. "PrintJob": "filename",
  29. "Attachment": "filename",
  30. "Manager": "filename",
  31. }
  32. # Fields that contain a dictionary keyed by filename.
  33. FILENAME_DICT_FIELDS = {
  34. "SubmissionResult": "executables",
  35. "UserTest": "managers",
  36. "UserTestResult": "executables",
  37. "Task": "attachments",
  38. "Dataset": "managers",
  39. }
  40. # Fields that contain filename schemas.
  41. FILENAME_SCHEMA_FIELDS = {
  42. "File": "filename",
  43. "UserTestFile": "filename",
  44. }
  45. # Fields that contain a dictionary keyed by filename schema.
  46. FILENAME_SCHEMA_DICT_FIELDS = {
  47. "Submission": "files",
  48. "UserTest": "files",
  49. }
  50. # Fields that contain arrays of filename schemas.
  51. FILENAME_SCHEMA_ARRAY_FIELDS = {
  52. "Task": "submission_format",
  53. }
  54. class Updater:
  55. def __init__(self, data):
  56. assert data["_version"] == 35
  57. self.objs = data
  58. self.warn = False
  59. def check_filename(self, filename):
  60. if "%" in filename:
  61. filename = filename.replace("%", "__")
  62. self.warn = True
  63. return filename
  64. def check_filename_schema(self, schema):
  65. if schema.endswith(".%l"):
  66. if "%" in schema[:-3]:
  67. schema = schema[:-3].replace("%", "__") + ".%l"
  68. self.warn = True
  69. elif "%" in schema:
  70. schema = schema.replace("%", "__")
  71. self.warn = True
  72. return schema
  73. def run(self):
  74. for k, v in self.objs.items():
  75. if k.startswith("_"):
  76. continue
  77. if v["_class"] in FILENAME_FIELDS:
  78. attr = FILENAME_FIELDS[v["_class"]]
  79. v[attr] = self.check_filename(v[attr])
  80. if v["_class"] in FILENAME_DICT_FIELDS:
  81. attr = FILENAME_DICT_FIELDS[v["_class"]]
  82. v[attr] = {self.check_filename(k): v
  83. for k, v in v[attr].items()}
  84. if v["_class"] in FILENAME_SCHEMA_FIELDS:
  85. attr = FILENAME_SCHEMA_FIELDS[v["_class"]]
  86. v[attr] = self.check_filename_schema(v[attr])
  87. if v["_class"] in FILENAME_SCHEMA_DICT_FIELDS:
  88. attr = FILENAME_SCHEMA_DICT_FIELDS[v["_class"]]
  89. v[attr] = {self.check_filename_schema(k): v
  90. for k, v in v[attr].items()}
  91. if v["_class"] in FILENAME_SCHEMA_ARRAY_FIELDS:
  92. attr = FILENAME_SCHEMA_ARRAY_FIELDS[v["_class"]]
  93. v[attr] = [self.check_filename_schema(schema)
  94. for schema in v[attr]]
  95. if self.warn:
  96. logger.warning("Some files contained '%' (the percent sign) in "
  97. "their names: this is now forbidden, and the "
  98. "occurrences have been replaced by '__'.")
  99. return self.objs