Commit 9d94adbd by Calen Pennington

Merge pull request #1871 from MITx/feature/cale/fast-dev-server

Speed up local development
parents 980fb92e 4d55f87a
...@@ -20,11 +20,8 @@ Longer TODO: ...@@ -20,11 +20,8 @@ Longer TODO:
""" """
import sys import sys
import os.path
import os
import lms.envs.common import lms.envs.common
from path import path from path import path
from xmodule.static_content import write_descriptor_styles, write_descriptor_js, write_module_js, write_module_styles
############################ FEATURE CONFIGURATION ############################# ############################ FEATURE CONFIGURATION #############################
...@@ -35,7 +32,7 @@ MITX_FEATURES = { ...@@ -35,7 +32,7 @@ MITX_FEATURES = {
'AUTH_USE_MIT_CERTIFICATES': False, 'AUTH_USE_MIT_CERTIFICATES': False,
'STUB_VIDEO_FOR_TESTING': False, # do not display video when running automated acceptance tests 'STUB_VIDEO_FOR_TESTING': False, # do not display video when running automated acceptance tests
'STAFF_EMAIL': '', # email address for staff (eg to request course creation) 'STAFF_EMAIL': '', # email address for staff (eg to request course creation)
'STUDIO_NPS_SURVEY': True, 'STUDIO_NPS_SURVEY': True,
'SEGMENT_IO': True, 'SEGMENT_IO': True,
} }
ENABLE_JASMINE = False ENABLE_JASMINE = False
...@@ -193,29 +190,7 @@ MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage' ...@@ -193,29 +190,7 @@ MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage' STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
# Load javascript and css from all of the available descriptors, and from rooted_paths import rooted_glob
# prep it for use in pipeline js
from xmodule.raw_module import RawDescriptor
from xmodule.error_module import ErrorDescriptor
from rooted_paths import rooted_glob, remove_root
write_descriptor_styles(PROJECT_ROOT / "static/sass/descriptor", [RawDescriptor, ErrorDescriptor])
write_module_styles(PROJECT_ROOT / "static/sass/module", [RawDescriptor, ErrorDescriptor])
descriptor_js = remove_root(
PROJECT_ROOT / 'static',
write_descriptor_js(
PROJECT_ROOT / "static/coffee/descriptor",
[RawDescriptor, ErrorDescriptor]
)
)
module_js = remove_root(
PROJECT_ROOT / 'static',
write_module_js(
PROJECT_ROOT / "static/coffee/module",
[RawDescriptor, ErrorDescriptor]
)
)
PIPELINE_CSS = { PIPELINE_CSS = {
'base-style': { 'base-style': {
...@@ -223,39 +198,35 @@ PIPELINE_CSS = { ...@@ -223,39 +198,35 @@ PIPELINE_CSS = {
'js/vendor/CodeMirror/codemirror.css', 'js/vendor/CodeMirror/codemirror.css',
'css/vendor/ui-lightness/jquery-ui-1.8.22.custom.css', 'css/vendor/ui-lightness/jquery-ui-1.8.22.custom.css',
'css/vendor/jquery.qtip.min.css', 'css/vendor/jquery.qtip.min.css',
'sass/base-style.scss' 'sass/base-style.css',
'xmodule/modules.css',
'xmodule/descriptor.css',
], ],
'output_filename': 'css/cms-base-style.css', 'output_filename': 'css/cms-base-style.css',
}, },
} }
PIPELINE_ALWAYS_RECOMPILE = ['sass/base-style.scss']
PIPELINE_JS = { PIPELINE_JS = {
'main': { 'main': {
'source_filenames': sorted( 'source_filenames': sorted(
rooted_glob(COMMON_ROOT / 'static/', 'coffee/src/**/*.coffee') + rooted_glob(COMMON_ROOT / 'static/', 'coffee/src/**/*.js') +
rooted_glob(PROJECT_ROOT / 'static/', 'coffee/src/**/*.coffee') rooted_glob(PROJECT_ROOT / 'static/', 'coffee/src/**/*.js')
) + ['js/hesitate.js', 'js/base.js'], ) + ['js/hesitate.js', 'js/base.js'],
'output_filename': 'js/cms-application.js', 'output_filename': 'js/cms-application.js',
}, },
'module-js': { 'module-js': {
'source_filenames': descriptor_js + module_js, 'source_filenames': (
rooted_glob(COMMON_ROOT / 'static/', 'xmodule/descriptors/js/*.js') +
rooted_glob(COMMON_ROOT / 'static/', 'xmodule/modules/js/*.js')
),
'output_filename': 'js/cms-modules.js', 'output_filename': 'js/cms-modules.js',
}, },
'spec': { 'spec': {
'source_filenames': sorted(rooted_glob(PROJECT_ROOT / 'static/', 'coffee/spec/**/*.coffee')), 'source_filenames': sorted(rooted_glob(PROJECT_ROOT / 'static/', 'coffee/spec/**/*.js')),
'output_filename': 'js/cms-spec.js' 'output_filename': 'js/cms-spec.js'
} }
} }
PIPELINE_COMPILERS = [
'pipeline.compilers.sass.SASSCompiler',
'pipeline.compilers.coffee.CoffeeScriptCompiler',
]
PIPELINE_SASS_ARGUMENTS = '-t compressed -r {proj_dir}/static/sass/bourbon/lib/bourbon.rb'.format(proj_dir=PROJECT_ROOT)
PIPELINE_CSS_COMPRESSOR = None PIPELINE_CSS_COMPRESSOR = None
PIPELINE_JS_COMPRESSOR = None PIPELINE_JS_COMPRESSOR = None
...@@ -267,11 +238,6 @@ STATICFILES_IGNORE_PATTERNS = ( ...@@ -267,11 +238,6 @@ STATICFILES_IGNORE_PATTERNS = (
) )
PIPELINE_YUI_BINARY = 'yui-compressor' PIPELINE_YUI_BINARY = 'yui-compressor'
PIPELINE_SASS_BINARY = 'sass'
PIPELINE_COFFEE_SCRIPT_BINARY = 'coffee'
# Setting that will only affect the MITx version of django-pipeline until our changes are merged upstream
PIPELINE_COMPILE_INPLACE = True
############################ APPS ##################################### ############################ APPS #####################################
......
...@@ -27,7 +27,7 @@ PIPELINE_JS['js-test-source'] = { ...@@ -27,7 +27,7 @@ PIPELINE_JS['js-test-source'] = {
} }
PIPELINE_JS['spec'] = { PIPELINE_JS['spec'] = {
'source_filenames': sorted(rooted_glob(PROJECT_ROOT / 'static/', 'coffee/spec/**/*.coffee')), 'source_filenames': sorted(rooted_glob(PROJECT_ROOT / 'static/', 'coffee/spec/**/*.js')),
'output_filename': 'js/cms-spec.js' 'output_filename': 'js/cms-spec.js'
} }
......
...@@ -54,5 +54,5 @@ ...@@ -54,5 +54,5 @@
@import 'assets/content-types'; @import 'assets/content-types';
// xblock-related // xblock-related
@import 'module/module-styles.scss'; @import 'xmodule/modules/css/module-styles.scss';
@import 'descriptor/module-styles.scss'; @import 'xmodule/descriptors/css/module-styles.scss';
../../../common/static/sass/bourbon/
\ No newline at end of file
...@@ -4,13 +4,15 @@ setup( ...@@ -4,13 +4,15 @@ setup(
name="XModule", name="XModule",
version="0.1", version="0.1",
packages=find_packages(exclude=["tests"]), packages=find_packages(exclude=["tests"]),
install_requires=['distribute'], install_requires=[
'distribute',
'docopt',
'capa',
'path.py',
],
package_data={ package_data={
'xmodule': ['js/module/*'] 'xmodule': ['js/module/*']
}, },
requires=[
'capa',
],
# See http://guide.python-distribute.org/creation.html#entry-points # See http://guide.python-distribute.org/creation.html#entry-points
# for a description of entry_points # for a description of entry_points
...@@ -50,6 +52,11 @@ setup( ...@@ -50,6 +52,11 @@ setup(
"graphical_slider_tool = xmodule.gst_module:GraphicalSliderToolDescriptor", "graphical_slider_tool = xmodule.gst_module:GraphicalSliderToolDescriptor",
"annotatable = xmodule.annotatable_module:AnnotatableDescriptor", "annotatable = xmodule.annotatable_module:AnnotatableDescriptor",
"foldit = xmodule.foldit_module:FolditDescriptor", "foldit = xmodule.foldit_module:FolditDescriptor",
] "hidden = xmodule.hidden_module:HiddenDescriptor",
"raw = xmodule.raw_module:RawDescriptor",
],
'console_scripts': [
'xmodule_assets = xmodule.static_content:main',
]
} }
) )
# /usr/bin/env python
""" """
This module has utility functions for gathering up the static content This module has utility functions for gathering up the static content
that is defined by XModules and XModuleDescriptors (javascript and css) that is defined by XModules and XModuleDescriptors (javascript and css)
...@@ -6,40 +7,43 @@ that is defined by XModules and XModuleDescriptors (javascript and css) ...@@ -6,40 +7,43 @@ that is defined by XModules and XModuleDescriptors (javascript and css)
import hashlib import hashlib
import os import os
import errno import errno
import sys
from collections import defaultdict from collections import defaultdict
from docopt import docopt
from path import path
from .x_module import XModuleDescriptor from xmodule.x_module import XModuleDescriptor
def write_module_styles(output_root, extra_descriptors): def write_module_styles(output_root):
return _write_styles('.xmodule_display', output_root, _list_modules(extra_descriptors)) return _write_styles('.xmodule_display', output_root, _list_modules())
def write_module_js(output_root, extra_descriptors): def write_module_js(output_root):
return _write_js(output_root, _list_modules(extra_descriptors)) return _write_js(output_root, _list_modules())
def write_descriptor_styles(output_root, extra_descriptors): def write_descriptor_styles(output_root):
return _write_styles('.xmodule_edit', output_root, _list_descriptors(extra_descriptors)) return _write_styles('.xmodule_edit', output_root, _list_descriptors())
def write_descriptor_js(output_root, extra_descriptors): def write_descriptor_js(output_root):
return _write_js(output_root, _list_descriptors(extra_descriptors)) return _write_js(output_root, _list_descriptors())
def _list_descriptors(extra_descriptors): def _list_descriptors():
return [ return [
desc for desc in [ desc for desc in [
desc for (_, desc) in XModuleDescriptor.load_classes() desc for (_, desc) in XModuleDescriptor.load_classes()
] + extra_descriptors ]
] ]
def _list_modules(extra_descriptors): def _list_modules():
return [ return [
desc.module_class desc.module_class
for desc for desc
in _list_descriptors(extra_descriptors) in _list_descriptors()
] ]
...@@ -76,9 +80,12 @@ def _write_styles(selector, output_root, classes): ...@@ -76,9 +80,12 @@ def _write_styles(selector, output_root, classes):
css_imports[class_].add(fragment_name) css_imports[class_].add(fragment_name)
with open(output_root / '_module-styles.scss', 'w') as module_styles: with open(output_root / '_module-styles.scss', 'w') as module_styles:
module_styles.write("@import 'bourbon/bourbon';\n")
module_styles.write("@import 'bourbon/addons/button';\n")
for class_, fragment_names in css_imports.items(): for class_, fragment_names in css_imports.items():
imports = "\n".join('@import "{0}";'.format(name) for name in fragment_names) imports = "\n".join('@import "{0}";'.format(name) for name in fragment_names)
module_styles.write("""{selector}.xmodule_{class_} {{ {imports} }}""".format( module_styles.write("""{selector}.xmodule_{class_} {{ {imports} }}\n""".format(
class_=class_, imports=imports, selector=selector class_=class_, imports=imports, selector=selector
)) ))
...@@ -105,3 +112,22 @@ def _write_js(output_root, classes): ...@@ -105,3 +112,22 @@ def _write_js(output_root, classes):
module_js.append(path) module_js.append(path)
return module_js return module_js
def main():
"""
Generate
Usage: static_content.py <output_root>
"""
args = docopt(main.__doc__)
root = path(args['<output_root>'])
root.rmtree(ignore_errors=True)
write_descriptor_js(root / 'descriptors/js')
write_descriptor_styles(root / 'descriptors/css')
write_module_js(root / 'modules/js')
write_module_styles(root / 'modules/css')
if __name__ == '__main__':
sys.exit(main())
...@@ -45,17 +45,13 @@ class HTMLSnippet(object): ...@@ -45,17 +45,13 @@ class HTMLSnippet(object):
# cdodge: We've moved the xmodule.coffee script from an outside directory into the xmodule area of common # cdodge: We've moved the xmodule.coffee script from an outside directory into the xmodule area of common
# this means we need to make sure that all xmodules include this dependency which had been previously implicitly # this means we need to make sure that all xmodules include this dependency which had been previously implicitly
# fulfilled in a different area of code # fulfilled in a different area of code
js = cls.js coffee = cls.js.setdefault('coffee', [])
fragment = resource_string(__name__, 'js/src/xmodule.coffee')
if js is None: if fragment not in coffee:
js = {} coffee.insert(0, fragment)
if 'coffee' not in js: return cls.js
js['coffee'] = []
js['coffee'].append(resource_string(__name__, 'js/src/xmodule.coffee'))
return js
@classmethod @classmethod
def get_css(cls): def get_css(cls):
...@@ -341,7 +337,7 @@ class XModuleDescriptor(XModuleFields, HTMLSnippet, ResourceTemplates, XBlock): ...@@ -341,7 +337,7 @@ class XModuleDescriptor(XModuleFields, HTMLSnippet, ResourceTemplates, XBlock):
# cdodge: this is a list of metadata names which are 'system' metadata # cdodge: this is a list of metadata names which are 'system' metadata
# and should not be edited by an end-user # and should not be edited by an end-user
system_metadata_fields = ['data_dir', 'published_date', 'published_by', 'is_draft', system_metadata_fields = ['data_dir', 'published_date', 'published_by', 'is_draft',
'discussion_id', 'xml_attributes'] 'discussion_id', 'xml_attributes']
# A list of descriptor attributes that must be equal for the descriptors to # A list of descriptor attributes that must be equal for the descriptors to
......
...@@ -38,6 +38,8 @@ source /mnt/virtualenvs/"$JOB_NAME"/bin/activate ...@@ -38,6 +38,8 @@ source /mnt/virtualenvs/"$JOB_NAME"/bin/activate
pip install -q -r pre-requirements.txt pip install -q -r pre-requirements.txt
yes w | pip install -q -r requirements.txt yes w | pip install -q -r requirements.txt
bundle install
rake clobber rake clobber
rake pep8 > pep8.log || cat pep8.log rake pep8 > pep8.log || cat pep8.log
rake pylint > pylint.log || cat pylint.log rake pylint > pylint.log || cat pylint.log
......
...@@ -20,7 +20,6 @@ Longer TODO: ...@@ -20,7 +20,6 @@ Longer TODO:
""" """
import sys import sys
import os import os
from xmodule.static_content import write_module_styles, write_module_js
from path import path from path import path
...@@ -392,21 +391,14 @@ MIDDLEWARE_CLASSES = ( ...@@ -392,21 +391,14 @@ MIDDLEWARE_CLASSES = (
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage' STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
from xmodule.hidden_module import HiddenDescriptor from rooted_paths import rooted_glob
from rooted_paths import rooted_glob, remove_root
write_module_styles(PROJECT_ROOT / 'static/sass/module', [HiddenDescriptor])
module_js = remove_root(
PROJECT_ROOT / 'static',
write_module_js(PROJECT_ROOT / 'static/coffee/module', [HiddenDescriptor])
)
courseware_js = ( courseware_js = (
[ [
'coffee/src/' + pth + '.coffee' 'coffee/src/' + pth + '.js'
for pth in ['courseware', 'histogram', 'navigation', 'time'] for pth in ['courseware', 'histogram', 'navigation', 'time']
] + ] +
sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/modules/**/*.coffee')) sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/modules/**/*.js'))
) )
# 'js/vendor/RequireJS.js' - Require JS wrapper. # 'js/vendor/RequireJS.js' - Require JS wrapper.
...@@ -422,13 +414,13 @@ main_vendor_js = [ ...@@ -422,13 +414,13 @@ main_vendor_js = [
'js/vendor/jquery.ba-bbq.min.js', 'js/vendor/jquery.ba-bbq.min.js',
] ]
discussion_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/discussion/**/*.coffee')) discussion_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/discussion/**/*.js'))
staff_grading_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/staff_grading/**/*.coffee')) staff_grading_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/staff_grading/**/*.js'))
open_ended_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/open_ended/**/*.coffee')) open_ended_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/open_ended/**/*.js'))
PIPELINE_CSS = { PIPELINE_CSS = {
'application': { 'application': {
'source_filenames': ['sass/application.scss'], 'source_filenames': ['sass/application.css'],
'output_filename': 'css/lms-application.css', 'output_filename': 'css/lms-application.css',
}, },
'course': { 'course': {
...@@ -437,24 +429,24 @@ PIPELINE_CSS = { ...@@ -437,24 +429,24 @@ PIPELINE_CSS = {
'css/vendor/jquery.treeview.css', 'css/vendor/jquery.treeview.css',
'css/vendor/ui-lightness/jquery-ui-1.8.22.custom.css', 'css/vendor/ui-lightness/jquery-ui-1.8.22.custom.css',
'css/vendor/jquery.qtip.min.css', 'css/vendor/jquery.qtip.min.css',
'sass/course.scss' 'sass/course.css',
'xmodule/modules.css',
], ],
'output_filename': 'css/lms-course.css', 'output_filename': 'css/lms-course.css',
}, },
'ie-fixes': { 'ie-fixes': {
'source_filenames': ['sass/ie.scss'], 'source_filenames': ['sass/ie.css'],
'output_filename': 'css/lms-ie.css', 'output_filename': 'css/lms-ie.css',
}, },
} }
PIPELINE_ALWAYS_RECOMPILE = ['sass/application.scss', 'sass/ie.scss', 'sass/course.scss']
PIPELINE_JS = { PIPELINE_JS = {
'application': { 'application': {
# Application will contain all paths not in courseware_only_js # Application will contain all paths not in courseware_only_js
'source_filenames': sorted( 'source_filenames': sorted(
set(rooted_glob(COMMON_ROOT / 'static', 'coffee/src/**/*.coffee') + set(rooted_glob(COMMON_ROOT / 'static', 'coffee/src/**/*.js') +
rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/**/*.coffee')) - rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/**/*.js')) -
set(courseware_js + discussion_js + staff_grading_js + open_ended_js) set(courseware_js + discussion_js + staff_grading_js + open_ended_js)
) + [ ) + [
'js/form.ext.js', 'js/form.ext.js',
...@@ -474,7 +466,7 @@ PIPELINE_JS = { ...@@ -474,7 +466,7 @@ PIPELINE_JS = {
'output_filename': 'js/lms-main_vendor.js', 'output_filename': 'js/lms-main_vendor.js',
}, },
'module-js': { 'module-js': {
'source_filenames': module_js, 'source_filenames': rooted_glob(COMMON_ROOT / 'static', 'xmodule/modules/js/*.js'),
'output_filename': 'js/lms-modules.js', 'output_filename': 'js/lms-modules.js',
}, },
'discussion': { 'discussion': {
...@@ -512,12 +504,6 @@ if os.path.isdir(DATA_DIR): ...@@ -512,12 +504,6 @@ if os.path.isdir(DATA_DIR):
os.system("rm %s" % (js_dir / new_filename)) os.system("rm %s" % (js_dir / new_filename))
os.system("coffee -c %s" % (js_dir / filename)) os.system("coffee -c %s" % (js_dir / filename))
PIPELINE_COMPILERS = [
'pipeline.compilers.sass.SASSCompiler',
'pipeline.compilers.coffee.CoffeeScriptCompiler',
]
PIPELINE_SASS_ARGUMENTS = '-t compressed -r {proj_dir}/static/sass/bourbon/lib/bourbon.rb'.format(proj_dir=PROJECT_ROOT)
PIPELINE_CSS_COMPRESSOR = None PIPELINE_CSS_COMPRESSOR = None
PIPELINE_JS_COMPRESSOR = None PIPELINE_JS_COMPRESSOR = None
...@@ -528,8 +514,6 @@ STATICFILES_IGNORE_PATTERNS = ( ...@@ -528,8 +514,6 @@ STATICFILES_IGNORE_PATTERNS = (
) )
PIPELINE_YUI_BINARY = 'yui-compressor' PIPELINE_YUI_BINARY = 'yui-compressor'
PIPELINE_SASS_BINARY = 'sass'
PIPELINE_COFFEE_SCRIPT_BINARY = 'coffee'
# Setting that will only affect the MITx version of django-pipeline until our changes are merged upstream # Setting that will only affect the MITx version of django-pipeline until our changes are merged upstream
PIPELINE_COMPILE_INPLACE = True PIPELINE_COMPILE_INPLACE = True
......
../../../common/static/sass/bourbon/
\ No newline at end of file
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
@import 'course/base/mixins'; @import 'course/base/mixins';
@import 'course/base/base'; @import 'course/base/base';
@import 'course/base/extends'; @import 'course/base/extends';
@import 'module/module-styles.scss'; @import 'xmodule/modules/css/module-styles.scss';
// courseware // courseware
@import 'course/courseware/courseware'; @import 'course/courseware/courseware';
......
{
"name": "mitx",
"version": "0.1.0",
"dependencies": { "coffee-script": "1.6.x"}
}
\ No newline at end of file
...@@ -21,15 +21,6 @@ COMMIT = (ENV["GIT_COMMIT"] || `git rev-parse HEAD`).chomp()[0, 10] ...@@ -21,15 +21,6 @@ COMMIT = (ENV["GIT_COMMIT"] || `git rev-parse HEAD`).chomp()[0, 10]
BRANCH = (ENV["GIT_BRANCH"] || `git symbolic-ref -q HEAD`).chomp().gsub('refs/heads/', '').gsub('origin/', '') BRANCH = (ENV["GIT_BRANCH"] || `git symbolic-ref -q HEAD`).chomp().gsub('refs/heads/', '').gsub('origin/', '')
BUILD_NUMBER = (ENV["BUILD_NUMBER"] || "dev").chomp() BUILD_NUMBER = (ENV["BUILD_NUMBER"] || "dev").chomp()
if BRANCH == "master"
DEPLOY_NAME = "#{PACKAGE_NAME}-#{BUILD_NUMBER}-#{COMMIT}"
else
DEPLOY_NAME = "#{PACKAGE_NAME}-#{BRANCH}-#{BUILD_NUMBER}-#{COMMIT}"
end
PACKAGE_REPO = "packages@gp.mitx.mit.edu:/opt/pkgrepo.incoming"
NORMALIZED_DEPLOY_NAME = DEPLOY_NAME.downcase().gsub(/[_\/]/, '-')
INSTALL_DIR_PATH = File.join(DEPLOY_DIR, NORMALIZED_DEPLOY_NAME)
# Set up the clean and clobber tasks # Set up the clean and clobber tasks
CLOBBER.include(BUILD_DIR, REPORT_DIR, 'test_root/*_repo', 'test_root/staticfiles') CLOBBER.include(BUILD_DIR, REPORT_DIR, 'test_root/*_repo', 'test_root/staticfiles')
CLEAN.include("#{BUILD_DIR}/*.deb", "#{BUILD_DIR}/util") CLEAN.include("#{BUILD_DIR}/*.deb", "#{BUILD_DIR}/util")
...@@ -43,16 +34,42 @@ def django_admin(system, env, command, *args) ...@@ -43,16 +34,42 @@ def django_admin(system, env, command, *args)
return "#{django_admin} #{command} --traceback --settings=#{system}.envs.#{env} --pythonpath=. #{args.join(' ')}" return "#{django_admin} #{command} --traceback --settings=#{system}.envs.#{env} --pythonpath=. #{args.join(' ')}"
end end
# Runs Process.spawn, and kills the process at the end of the rake process
# Expects the same arguments as Process.spawn
def background_process(*command)
pid = Process.spawn({}, *command, {:pgroup => true})
at_exit do
puts "Ending process and children"
pgid = Process.getpgid(pid)
begin
Timeout.timeout(5) do
puts "Terminating process group #{pgid}"
Process.kill(:SIGTERM, -pgid)
puts "Waiting on process group #{pgid}"
Process.wait(-pgid)
puts "Done waiting on process group #{pgid}"
end
rescue Timeout::Error
puts "Killing process group #{pgid}"
Process.kill(:SIGKILL, -pgid)
puts "Waiting on process group #{pgid}"
Process.wait(-pgid)
puts "Done waiting on process group #{pgid}"
end
end
end
def django_for_jasmine(system, django_reload) def django_for_jasmine(system, django_reload)
if !django_reload if !django_reload
reload_arg = '--noreload' reload_arg = '--noreload'
end end
port = 10000 + rand(40000) port = 10000 + rand(40000)
django_pid = fork do
exec(*django_admin(system, 'jasmine', 'runserver', '-v', '0', port.to_s, reload_arg).split(' '))
end
jasmine_url = "http://localhost:#{port}/_jasmine/" jasmine_url = "http://localhost:#{port}/_jasmine/"
background_process(*django_admin(system, 'jasmine', 'runserver', '-v', '0', port.to_s, reload_arg).split(' '))
up = false up = false
start_time = Time.now start_time = Time.now
until up do until up do
...@@ -70,16 +87,7 @@ def django_for_jasmine(system, django_reload) ...@@ -70,16 +87,7 @@ def django_for_jasmine(system, django_reload)
sleep(0.5) sleep(0.5)
end end
end end
begin yield jasmine_url
yield jasmine_url
ensure
if django_reload
Process.kill(:SIGKILL, -Process.getpgid(django_pid))
else
Process.kill(:SIGKILL, django_pid)
end
Process.wait(django_pid)
end
end end
def template_jasmine_runner(lib) def template_jasmine_runner(lib)
...@@ -111,6 +119,33 @@ def report_dir_path(dir) ...@@ -111,6 +119,33 @@ def report_dir_path(dir)
return File.join(REPORT_DIR, dir.to_s) return File.join(REPORT_DIR, dir.to_s)
end end
def compile_assets(watch=false, debug=false)
xmodule_cmd = 'xmodule_assets common/static/xmodule'
if watch
xmodule_cmd = "watchmedo shell-command \
--patterns='*.js;*.coffee;*.sass;*.scss;*.css' \
--recursive \
--command='#{xmodule_cmd}' \
common/lib/xmodule"
end
coffee_cmd = "coffee #{watch ? '--watch' : ''} --compile */static"
sass_cmd = "sass #{debug ? '--debug-info' : '--style compressed'} " +
"--load-path ./common/static/sass " +
"--require ./common/static/sass/bourbon/lib/bourbon.rb " +
"#{watch ? '--watch' : '--update --force'} */static"
[xmodule_cmd, coffee_cmd, sass_cmd].each do |cmd|
if watch
background_process(cmd)
else
pid = Process.spawn(cmd)
puts "Waiting for `#{cmd}` to complete (pid #{pid})"
Process.wait(pid)
puts "Completed"
end
end
end
task :default => [:test, :pep8, :pylint] task :default => [:test, :pep8, :pylint]
directory REPORT_DIR directory REPORT_DIR
...@@ -195,7 +230,7 @@ end ...@@ -195,7 +230,7 @@ end
# Per System tasks # Per System tasks
desc "Run all django tests on our djangoapps for the #{system}" desc "Run all django tests on our djangoapps for the #{system}"
task "test_#{system}", [:stop_on_failure] => ["clean_test_files", "#{system}:collectstatic:test", "fasttest_#{system}"] task "test_#{system}", [:stop_on_failure] => ["clean_test_files", "#{system}:gather_assets:test", "fasttest_#{system}"]
# Have a way to run the tests without running collectstatic -- useful when debugging without # Have a way to run the tests without running collectstatic -- useful when debugging without
# messing with static files. # messing with static files.
...@@ -214,6 +249,13 @@ end ...@@ -214,6 +249,13 @@ end
desc desc
task system, [:env, :options] => [:predjango] do |t, args| task system, [:env, :options] => [:predjango] do |t, args|
args.with_defaults(:env => 'dev', :options => default_options[system]) args.with_defaults(:env => 'dev', :options => default_options[system])
# Compile all assets first
compile_assets(watch=false, debug=true)
# Listen for any changes to assets
compile_assets(watch=true, debug=true)
sh(django_admin(system, args.env, 'runserver', args.options)) sh(django_admin(system, args.env, 'runserver', args.options))
end end
...@@ -225,9 +267,10 @@ end ...@@ -225,9 +267,10 @@ end
sh("echo 'import #{system}.envs.#{env}' | #{django_admin(system, env, 'shell')}") sh("echo 'import #{system}.envs.#{env}' | #{django_admin(system, env, 'shell')}")
end end
desc "Run collectstatic in the specified environment" desc "Compile coffeescript and sass, and then run collectstatic in the specified environment"
task "#{system}:collectstatic:#{env}" => :predjango do task "#{system}:gather_assets:#{env}" do
sh("#{django_admin(system, env, 'collectstatic', '--noinput')} > /tmp/collectstatic.out") do |ok, status| compile_assets()
sh("#{django_admin(system, env, 'collectstatic', '--noinput')} > /dev/null") do |ok, status|
if !ok if !ok
abort "collectstatic failed!" abort "collectstatic failed!"
end end
...@@ -353,7 +396,7 @@ end ...@@ -353,7 +396,7 @@ end
task :runserver => :lms task :runserver => :lms
desc "Run django-admin <action> against the specified system and environment" desc "Run django-admin <action> against the specified system and environment"
task "django-admin", [:action, :system, :env, :options] => [:predjango] do |t, args| task "django-admin", [:action, :system, :env, :options] do |t, args|
args.with_defaults(:env => 'dev', :system => 'lms', :options => '') args.with_defaults(:env => 'dev', :system => 'lms', :options => '')
sh(django_admin(args.system, args.env, args.action, args.options)) sh(django_admin(args.system, args.env, args.action, args.options))
end end
...@@ -364,51 +407,6 @@ task :set_staff, [:user, :system, :env] do |t, args| ...@@ -364,51 +407,6 @@ task :set_staff, [:user, :system, :env] do |t, args|
sh(django_admin(args.system, args.env, 'set_staff', args.user)) sh(django_admin(args.system, args.env, 'set_staff', args.user))
end end
task :package do
FileUtils.mkdir_p(BUILD_DIR)
Dir.chdir(BUILD_DIR) do
afterremove = Tempfile.new('afterremove')
afterremove.write <<-AFTERREMOVE.gsub(/^\s*/, '')
#! /bin/bash
set -e
set -x
# to be a little safer this rm is executed
# as the makeitso user
if [[ -d "#{INSTALL_DIR_PATH}" ]]; then
sudo rm -rf "#{INSTALL_DIR_PATH}"
fi
AFTERREMOVE
afterremove.close()
FileUtils.chmod(0755, afterremove.path)
args = ["fakeroot", "fpm", "-s", "dir", "-t", "deb",
"--after-remove=#{afterremove.path}",
"--prefix=#{INSTALL_DIR_PATH}",
"--exclude=**/build/**",
"--exclude=**/rakefile",
"--exclude=**/.git/**",
"--exclude=**/*.pyc",
"--exclude=**/reports/**",
"--exclude=**/test_root/**",
"--exclude=**/.coverage/**",
"-C", "#{REPO_ROOT}",
"--provides=#{PACKAGE_NAME}",
"--name=#{NORMALIZED_DEPLOY_NAME}",
"--version=#{PKG_VERSION}",
"-a", "all",
"."]
system(*args) || raise("fpm failed to build the .deb")
end
end
task :publish => :package do
sh("scp #{BUILD_DIR}/#{NORMALIZED_DEPLOY_NAME}_#{PKG_VERSION}*.deb #{PACKAGE_REPO}")
end
namespace :cms do namespace :cms do
desc "Clone existing MongoDB based course" desc "Clone existing MongoDB based course"
task :clone do task :clone do
...@@ -419,9 +417,7 @@ namespace :cms do ...@@ -419,9 +417,7 @@ namespace :cms do
raise "You must pass in a SOURCE_LOC and DEST_LOC parameters" raise "You must pass in a SOURCE_LOC and DEST_LOC parameters"
end end
end end
end
namespace :cms do
desc "Delete existing MongoDB based course" desc "Delete existing MongoDB based course"
task :delete_course do task :delete_course do
...@@ -433,9 +429,7 @@ namespace :cms do ...@@ -433,9 +429,7 @@ namespace :cms do
raise "You must pass in a LOC parameter" raise "You must pass in a LOC parameter"
end end
end end
end
namespace :cms do
desc "Import course data within the given DATA_DIR variable" desc "Import course data within the given DATA_DIR variable"
task :import do task :import do
if ENV['DATA_DIR'] and ENV['COURSE_DIR'] if ENV['DATA_DIR'] and ENV['COURSE_DIR']
...@@ -447,16 +441,12 @@ namespace :cms do ...@@ -447,16 +441,12 @@ namespace :cms do
"Example: \`rake cms:import DATA_DIR=../data\`" "Example: \`rake cms:import DATA_DIR=../data\`"
end end
end end
end
namespace :cms do
desc "Imports all the templates from the code pack" desc "Imports all the templates from the code pack"
task :update_templates do task :update_templates do
sh(django_admin(:cms, :dev, :update_templates)) sh(django_admin(:cms, :dev, :update_templates))
end end
end
namespace :cms do
desc "Import course data within the given DATA_DIR variable" desc "Import course data within the given DATA_DIR variable"
task :xlint do task :xlint do
if ENV['DATA_DIR'] and ENV['COURSE_DIR'] if ENV['DATA_DIR'] and ENV['COURSE_DIR']
...@@ -468,9 +458,7 @@ namespace :cms do ...@@ -468,9 +458,7 @@ namespace :cms do
"Example: \`rake cms:import DATA_DIR=../data\`" "Example: \`rake cms:import DATA_DIR=../data\`"
end end
end end
end
namespace :cms do
desc "Export course data to a tar.gz file" desc "Export course data to a tar.gz file"
task :export do task :export do
if ENV['COURSE_ID'] and ENV['OUTPUT_PATH'] if ENV['COURSE_ID'] and ENV['OUTPUT_PATH']
......
...@@ -51,6 +51,8 @@ xmltodict==0.4.1 ...@@ -51,6 +51,8 @@ xmltodict==0.4.1
# Used for debugging # Used for debugging
ipython==0.13.1 ipython==0.13.1
# Used for development operation
watchdog==0.6.0
# Metrics gathering and monitoring # Metrics gathering and monitoring
dogapi==1.2.1 dogapi==1.2.1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment