diff --git a/.gitignore b/.gitignore index 9c82bb8ea9..05e76c4caa 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ Gemfile.lock conf/locale/en/LC_MESSAGES/*.po !messages.po lms/static/sass/*.css +lms/static/sass/application.scss cms/static/sass/*.css lms/lib/comment_client/python nosetests.xml diff --git a/lms/envs/aws.py b/lms/envs/aws.py index df80d5a924..a3d5cb653f 100644 --- a/lms/envs/aws.py +++ b/lms/envs/aws.py @@ -114,6 +114,11 @@ DEFAULT_FEEDBACK_EMAIL = ENV_TOKENS.get('DEFAULT_FEEDBACK_EMAIL', DEFAULT_FEEDBA ADMINS = ENV_TOKENS.get('ADMINS', ADMINS) SERVER_EMAIL = ENV_TOKENS.get('SERVER_EMAIL', SERVER_EMAIL) +#Theme overrides +THEME_NAME = ENV_TOKENS.get('THEME_NAME', None) +if not THEME_NAME is None: + enable_theme(THEME_NAME) + #Timezone overrides TIME_ZONE = ENV_TOKENS.get('TIME_ZONE', TIME_ZONE) diff --git a/lms/envs/common.py b/lms/envs/common.py index 3c133a1e6b..64012d1f53 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -110,6 +110,9 @@ MITX_FEATURES = { # Enable URL that shows information about the status of variuous services 'ENABLE_SERVICE_STATUS': False, + + # Toggle to indicate use of a custom theme + 'USE_CUSTOM_THEME': False } # Used for A/B testing @@ -167,12 +170,12 @@ MAKO_TEMPLATES['main'] = [PROJECT_ROOT / 'templates', # This is where Django Template lookup is defined. There are a few of these # still left lying around. -TEMPLATE_DIRS = ( +TEMPLATE_DIRS = [ PROJECT_ROOT / "templates", COMMON_ROOT / 'templates', COMMON_ROOT / 'lib' / 'capa' / 'capa' / 'templates', COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates', -) +] TEMPLATE_CONTEXT_PROCESSORS = ( 'django.core.context_processors.request', @@ -714,3 +717,31 @@ MKTG_URL_LINK_MAP = { 'HONOR': 'honor', 'PRIVACY': 'privacy_edx', } + +############################### THEME ################################ +def enable_theme(theme_name): + """ + Enable the settings for a custom theme, whose files should be stored + in ENV_ROOT/themes/THEME_NAME (e.g., edx_all/themes/stanford). + + The THEME_NAME setting should be configured separately since it can't + be set here (this function closes too early). An idiom for doing this + is: + + THEME_NAME = "stanford" + enable_theme(THEME_NAME) + """ + MITX_FEATURES['USE_CUSTOM_THEME'] = True + + # Calculate the location of the theme's files + theme_root = ENV_ROOT / "themes" / theme_name + + # Include the theme's templates in the template search paths + TEMPLATE_DIRS.append(theme_root / 'templates') + MAKO_TEMPLATES['main'].append(theme_root / 'templates') + + # Namespace the theme's static files to 'themes/' to + # avoid collisions with default edX static files + STATICFILES_DIRS.append((u'themes/%s' % theme_name, + theme_root / 'static')) + diff --git a/lms/static/sass/application.scss b/lms/static/sass/application.scss.mako similarity index 63% rename from lms/static/sass/application.scss rename to lms/static/sass/application.scss.mako index 6a1ef8743e..434475c6ac 100644 --- a/lms/static/sass/application.scss +++ b/lms/static/sass/application.scss.mako @@ -36,3 +36,16 @@ @import 'news'; @import 'shame'; + +## THEMING +## ------- +## Set up this file to import an edX theme library if the environment +## indicates that a theme should be used. The assumption is that the +## theme resides outside of this main edX repository, in a directory +## called themes//, with its base Sass file in +## themes//static/sass/_.scss. That one entry +## point can be used to @import in as many other things as needed. +% if not env['THEME_NAME'] is None: + // import theme's Sass overrides + @import '${env['THEME_NAME']}' +% endif diff --git a/rakefile b/rakefile index cef93e67eb..20101a14db 100644 --- a/rakefile +++ b/rakefile @@ -1,3 +1,4 @@ +require 'json' require 'rake/clean' require './rakefiles/helpers.rb' @@ -7,6 +8,13 @@ end # Build Constants REPO_ROOT = File.dirname(__FILE__) +ENV_ROOT = File.dirname(REPO_ROOT) REPORT_DIR = File.join(REPO_ROOT, "reports") +# Environment constants +SERVICE_VARIANT = ENV['SERVICE_VARIANT'] +CONFIG_PREFIX = SERVICE_VARIANT ? SERVICE_VARIANT + "." : "" +ENV_FILE = File.join(ENV_ROOT, CONFIG_PREFIX + "env.json") +ENV_TOKENS = File.exists?(ENV_FILE) ? JSON.parse(File.read(ENV_FILE)) : {} + task :default => [:test, :pep8, :pylint] diff --git a/rakefiles/assets.rake b/rakefiles/assets.rake index 0369968fdf..ef77d4fea7 100644 --- a/rakefiles/assets.rake +++ b/rakefiles/assets.rake @@ -1,3 +1,36 @@ +# Theming constants +THEME_NAME = ENV_TOKENS['THEME_NAME'] +USE_CUSTOM_THEME = !(THEME_NAME.nil? || THEME_NAME.empty?) +if USE_CUSTOM_THEME + THEME_ROOT = File.join(ENV_ROOT, "themes", THEME_NAME) + THEME_SASS = File.join(THEME_ROOT, "static", "sass") +end + +# Run the specified file through the Mako templating engine, providing +# the ENV_TOKENS to the templating context. +def preprocess_with_mako(filename) + # simple command-line invocation of Mako engine + mako = "from mako.template import Template;" + + "print Template(filename=\"#{filename}\")" + + # Total hack. It works because a Python dict literal has + # the same format as a JSON object. + ".render(env=#{ENV_TOKENS.to_json});" + + # strip off the .mako extension + output_filename = filename.chomp(File.extname(filename)) + + # just pipe from stdout into the new file + File.open(output_filename, 'w') do |file| + file.write(`python -c '#{mako}'`) + end +end + +# Preprocess all static assets that have the .mako extension by +# running them through the Mako templating engine. Right now we +# just hardcode the asset filenames. +def preprocess_assets + preprocess_with_mako("lms/static/sass/application.scss.mako") +end def xmodule_cmd(watch=false, debug=false) xmodule_cmd = 'xmodule_assets common/static/xmodule' @@ -32,10 +65,20 @@ def coffee_cmd(watch=false, debug=false) end def sass_cmd(watch=false, debug=false) + # Make sure to preprocess templatized Sass first + preprocess_assets() + + sass_load_paths = ["./common/static/sass"] + sass_watch_paths = ["*/static"] + if USE_CUSTOM_THEME + sass_load_paths << THEME_SASS + sass_watch_paths << THEME_SASS + end + "sass #{debug ? '--debug-info' : '--style compressed'} " + - "--load-path ./common/static/sass " + + "--load-path #{sass_load_paths.join(' ')} " + "--require ./common/static/sass/bourbon/lib/bourbon.rb " + - "#{watch ? '--watch' : '--update'} */static" + "#{watch ? '--watch' : '--update'} #{sass_watch_paths.join(' ')}" end desc "Compile all assets"