def get_all_courses(rules_text=None): """Reads all course rewrite rule definitions from environment variable.""" # Normalize text definition. if not rules_text: rules_text = GCB_COURSES_CONFIG.value rules_text = rules_text.replace(',', '\n') # Use cached value if exists. cached = ApplicationContext.ALL_COURSE_CONTEXTS_CACHE.get(rules_text) if cached: return cached # Compute the list of contexts. rules = rules_text.split('\n') slugs = {} namespaces = {} all_contexts = [] for rule in rules: rule = rule.strip() if not rule or rule.startswith('#'): continue parts = rule.split(':') # validate length if len(parts) < 3: raise Exception('Expected rule definition of the form ' ' \'type:slug:folder[:ns]\', got %s: ' % rule) # validate type if parts[0] != SITE_TYPE_COURSE: raise Exception('Expected \'%s\', found: \'%s\'.' % (SITE_TYPE_COURSE, parts[0])) site_type = parts[0] # validate slug slug = parts[1] slug_parts = urlparse.urlparse(slug) if slug != slug_parts[2]: raise Exception( 'Bad rule: \'%s\'. ' 'Course URL prefix \'%s\' must be a simple URL fragment.' % ( rule, slug)) if slug in slugs: raise Exception( 'Bad rule: \'%s\'. ' 'Course URL prefix \'%s\' is already defined.' % (rule, slug)) slugs[slug] = True # validate folder name if parts[2]: folder = parts[2] # pylint: disable-msg=g-long-lambda create_fs = lambda unused_ns: LocalReadOnlyFileSystem( logical_home_folder=folder) else: folder = '/' # pylint: disable-msg=g-long-lambda create_fs = lambda ns: DatastoreBackedFileSystem( ns=ns, logical_home_folder=appengine_config.BUNDLE_ROOT, inherits_from=LocalReadOnlyFileSystem(logical_home_folder='/'), inheritable_folders=GCB_INHERITABLE_FOLDER_NAMES) # validate or derive namespace namespace = appengine_config.DEFAULT_NAMESPACE_NAME if len(parts) == 4: namespace = parts[3] else: if folder and folder != '/': namespace = '%s%s' % (GCB_BASE_COURSE_NAMESPACE, folder.replace('/', '-')) try: namespace_manager.validate_namespace(namespace) except Exception as e: raise Exception( 'Error validating namespace "%s" in rule "%s"; %s.' % ( namespace, rule, e)) if namespace in namespaces: raise Exception( 'Bad rule \'%s\'. ' 'Namespace \'%s\' is already defined.' % (rule, namespace)) namespaces[namespace] = True all_contexts.append(ApplicationContext( site_type, slug, folder, namespace, AbstractFileSystem(create_fs(namespace)), raw=rule)) _validate_appcontext_list(all_contexts) # Cache result to avoid re-parsing over and over. ApplicationContext.ALL_COURSE_CONTEXTS_CACHE = {rules_text: all_contexts} return all_contexts