Initial version of import/check/export script.
* uses xml modulestore, and new error_handler hook
This commit is contained in:
143
lms/djangoapps/courseware/management/commands/clean_xml.py
Normal file
143
lms/djangoapps/courseware/management/commands/clean_xml.py
Normal file
@@ -0,0 +1,143 @@
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from fs.osfs import OSFS
|
||||
from path import path
|
||||
from lxml import etree
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from xmodule.modulestore.xml import XMLModuleStore
|
||||
|
||||
|
||||
def export(course, export_dir):
|
||||
"""Export the specified course to course_dir. Creates dir if it doesn't exist.
|
||||
Overwrites files, does not clean out dir beforehand.
|
||||
"""
|
||||
fs = OSFS(export_dir, create=True)
|
||||
if not fs.isdirempty('.'):
|
||||
print ('WARNING: Directory {dir} not-empty.'
|
||||
' May clobber/confuse things'.format(dir=export_dir))
|
||||
|
||||
try:
|
||||
xml = course.export_to_xml(fs)
|
||||
with fs.open('course.xml', mode='w') as f:
|
||||
f.write(xml)
|
||||
|
||||
return True
|
||||
except:
|
||||
print 'Export failed!'
|
||||
traceback.print_exc()
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def traverse_tree(course):
|
||||
'''Load every descriptor in course. Return bool success value.'''
|
||||
queue = [course]
|
||||
while len(queue) > 0:
|
||||
node = queue.pop()
|
||||
# print '{0}:'.format(node.location)
|
||||
# if 'data' in node.definition:
|
||||
# print '{0}'.format(node.definition['data'])
|
||||
queue.extend(node.get_children())
|
||||
|
||||
return True
|
||||
|
||||
def make_logging_error_handler():
|
||||
'''Return a tuple (handler, error_list), where
|
||||
the handler appends the message and any exc_info
|
||||
to the error_list on every call.
|
||||
'''
|
||||
errors = []
|
||||
|
||||
def error_handler(msg, exc_info=None):
|
||||
'''Log errors'''
|
||||
if exc_info is None:
|
||||
if sys.exc_info() != (None, None, None):
|
||||
exc_info = sys.exc_info()
|
||||
|
||||
errors.append((msg, exc_info))
|
||||
|
||||
return (error_handler, errors)
|
||||
|
||||
def clean_xml(course_dir, export_dir, verbose=True):
|
||||
all_ok = True
|
||||
|
||||
print "Attempting to load '{0}'".format(course_dir)
|
||||
|
||||
course_dir = path(course_dir)
|
||||
data_dir = course_dir.dirname()
|
||||
course_dirs = [course_dir.basename()]
|
||||
|
||||
(error_handler, errors) = make_logging_error_handler()
|
||||
# No default class--want to complain if it doesn't find plugins for any
|
||||
# module.
|
||||
modulestore = XMLModuleStore(data_dir,
|
||||
default_class=None,
|
||||
eager=True,
|
||||
course_dirs=course_dirs,
|
||||
error_handler=error_handler)
|
||||
|
||||
def str_of_err(tpl):
|
||||
(msg, exc_info) = tpl
|
||||
if exc_info is None:
|
||||
return msg
|
||||
|
||||
exc_str = '\n'.join(traceback.format_exception(*exc_info))
|
||||
return '{msg}\n{exc}'.format(msg=msg, exc=exc_str)
|
||||
|
||||
courses = modulestore.get_courses()
|
||||
if len(errors) != 0:
|
||||
all_ok = False
|
||||
print '\n'
|
||||
print "=" * 40
|
||||
print 'ERRORs during import:'
|
||||
print '\n'.join(map(str_of_err,errors))
|
||||
print "=" * 40
|
||||
print '\n'
|
||||
|
||||
n = len(courses)
|
||||
if n != 1:
|
||||
print 'ERROR: Expect exactly 1 course. Loaded {n}: {lst}'.format(
|
||||
n=n, lst=courses)
|
||||
return
|
||||
|
||||
course = courses[0]
|
||||
|
||||
print course
|
||||
validators = (
|
||||
traverse_tree,
|
||||
)
|
||||
|
||||
print "=" * 40
|
||||
print "Running validators..."
|
||||
|
||||
for validate in validators:
|
||||
print 'Running {0}'.format(validate.__name__)
|
||||
all_ok = validate(course) and all_ok
|
||||
|
||||
|
||||
if all_ok:
|
||||
print 'Course passes all checks!'
|
||||
export(course, export_dir)
|
||||
|
||||
else:
|
||||
print "Course fails some checks. See above for errors."
|
||||
print "Did NOT export"
|
||||
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = """Imports specified course.xml, validate it, then exports in
|
||||
a canonical format.
|
||||
|
||||
Usage: clean_xml PATH-TO-COURSE-DIR PATH-TO-OUTPUT-DIR
|
||||
"""
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if len(args) != 2:
|
||||
print Command.help
|
||||
return
|
||||
|
||||
clean_xml(args[0], args[1])
|
||||
Reference in New Issue
Block a user