initial buildout of a 'xlint' test to verify legacy coursewar
This commit is contained in:
26
cms/djangoapps/contentstore/management/commands/xlint.py
Normal file
26
cms/djangoapps/contentstore/management/commands/xlint.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from xmodule.modulestore.xml_importer import import_from_xml
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.contentstore.django import contentstore
|
||||
|
||||
|
||||
unnamed_modules = 0
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = \
|
||||
'''Verify the structure of courseware as to it's suitability for import'''
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if len(args) == 0:
|
||||
raise CommandError("import requires at least one argument: <data directory> [<course dir>...]")
|
||||
|
||||
data_dir = args[0]
|
||||
if len(args) > 1:
|
||||
course_dirs = args[1:]
|
||||
else:
|
||||
course_dirs = None
|
||||
print "Importing. Data_dir={data}, course_dirs={courses}".format(
|
||||
data=data_dir,
|
||||
courses=course_dirs)
|
||||
import_from_xml(None, data_dir, course_dirs, load_error_modules=False, validate_only=True)
|
||||
@@ -88,7 +88,7 @@ def verify_content_links(module, base_dir, static_content_store, link, remap_dic
|
||||
|
||||
def import_from_xml(store, data_dir, course_dirs=None,
|
||||
default_class='xmodule.raw_module.RawDescriptor',
|
||||
load_error_modules=True, static_content_store=None, target_location_namespace = None):
|
||||
load_error_modules=True, static_content_store=None, target_location_namespace=None, validate_only=False):
|
||||
"""
|
||||
Import the specified xml data_dir into the "store" modulestore,
|
||||
using org and course as the location org and course.
|
||||
@@ -110,6 +110,10 @@ def import_from_xml(store, data_dir, course_dirs=None,
|
||||
load_error_modules=load_error_modules
|
||||
)
|
||||
|
||||
if validate_only:
|
||||
validate_module_structure(module_store)
|
||||
return module_store, []
|
||||
|
||||
# NOTE: the XmlModuleStore does not implement get_items() which would be a preferable means
|
||||
# to enumerate the entire collection of course modules. It will be left as a TBD to implement that
|
||||
# method on XmlModuleStore.
|
||||
@@ -192,7 +196,6 @@ def import_from_xml(store, data_dir, course_dirs=None,
|
||||
|
||||
store.update_item(module.location, module_data)
|
||||
|
||||
|
||||
if 'children' in module.definition:
|
||||
store.update_children(module.location, module.definition['children'])
|
||||
|
||||
@@ -200,6 +203,38 @@ def import_from_xml(store, data_dir, course_dirs=None,
|
||||
# inherited metadata everywhere.
|
||||
store.update_metadata(module.location, dict(module.own_metadata))
|
||||
|
||||
|
||||
|
||||
return module_store, course_items
|
||||
|
||||
|
||||
def validate_category_hierarcy(module_store, course_id, parent_category, expected_child_category):
|
||||
err_cnt = 0
|
||||
|
||||
parents = []
|
||||
# get all modules of parent_category
|
||||
for module in module_store.modules[course_id].itervalues():
|
||||
if module.location.category == parent_category:
|
||||
parents.append(module)
|
||||
|
||||
for parent in parents:
|
||||
for child_loc in [Location(child) for child in parent.definition.get('children', [])]:
|
||||
if child_loc.category != expected_child_category:
|
||||
err_cnt += 1
|
||||
print 'ERROR: child {0} of parent {1} was expected to be category of {2} but was {3}'.format(
|
||||
child_loc, parent.location, expected_child_category, child_loc.category)
|
||||
|
||||
return err_cnt
|
||||
|
||||
def validate_module_structure(module_store):
|
||||
err_cnt = 0
|
||||
warn_cnt = 0
|
||||
for course_id in module_store.modules.keys():
|
||||
# constrain that courses only have 'chapter' children
|
||||
err_cnt += validate_category_hierarcy(module_store, course_id, "course", "chapter")
|
||||
# constrain that chapters only have 'sequentials'
|
||||
err_cnt += validate_category_hierarcy(module_store, course_id, "chapter", "sequential")
|
||||
# constrain that sequentials only have 'verticals'
|
||||
err_cnt += validate_category_hierarcy(module_store, course_id, "sequential", "vertical")
|
||||
|
||||
print "SUMMARY: {0} Errors {1} Warnings".format(err_cnt, warn_cnt)
|
||||
|
||||
|
||||
|
||||
12
rakefile
12
rakefile
@@ -364,6 +364,18 @@ namespace :cms do
|
||||
end
|
||||
end
|
||||
|
||||
namespace :cms do
|
||||
desc "Import course data within the given DATA_DIR variable"
|
||||
task :xlint do
|
||||
if ENV['DATA_DIR']
|
||||
sh(django_admin(:cms, :dev, :xlint, ENV['DATA_DIR']))
|
||||
else
|
||||
raise "Please specify a DATA_DIR variable that point to your data directory.\n" +
|
||||
"Example: \`rake cms:import DATA_DIR=../data\`"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Build a properties file used to trigger autodeploy builds"
|
||||
task :autodeploy_properties do
|
||||
File.open("autodeploy.properties", "w") do |file|
|
||||
|
||||
Reference in New Issue
Block a user