319 lines
16 KiB
Python
Executable file
319 lines
16 KiB
Python
Executable file
from optparse import make_option
|
|
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess # since python 2.4
|
|
import sys
|
|
from dojango.conf import settings
|
|
|
|
try:
|
|
from django.core.management.base import BaseCommand, CommandError
|
|
except ImportError:
|
|
# Fake BaseCommand out so imports on django 0.96 don't fail.
|
|
BaseCommand = object
|
|
class CommandError(Exception):
|
|
pass
|
|
|
|
class Command(BaseCommand):
|
|
'''This command is used to create your own dojo build. To start a build, you just
|
|
have to type:
|
|
|
|
./manage.py dojobuild
|
|
|
|
in your django project path. With this call, the default build profile "dojango" is used
|
|
and dojango.profile.js will act as its dojo build configuration. You can also add the
|
|
option --build_version=dev1.1.1 (for example) to mark the build with it.
|
|
If you want to call a specific build profile from DOJO_BUILD_PROFILES, you just have to
|
|
append the profile name to this commandline call:
|
|
|
|
./manage.py dojobuild profilename
|
|
|
|
'''
|
|
|
|
option_list = BaseCommand.option_list + (
|
|
make_option('--build_version', dest='build_version',
|
|
help='Set the version of the build release (e.g. dojango_1.1.1).'),
|
|
make_option('--minify', dest='minify', action="store_true", default=False,
|
|
help='Does a dojo mini build (mainly removing unneeded files (tests/templates/...)'),
|
|
make_option('--minify_extreme', dest='minify_extreme', action="store_true", default=False,
|
|
help='Does a dojo extreme-mini build (keeps only what is defined in build profile and all media files)'),
|
|
make_option('--prepare_zipserve', dest='prepare_zipserve', action="store_true", default=False,
|
|
help='Zips everything you have built, so it can be deployed to Google AppEngine'),
|
|
)
|
|
help = "Builds a dojo release."
|
|
args = '[dojo build profile name]'
|
|
dojo_base_dir = None
|
|
dojo_release_dir = None
|
|
skip_files = None
|
|
|
|
def handle(self, *args, **options):
|
|
if len(args)==0:
|
|
# with no param, we use the default profile, that is defined in the settings
|
|
profile_name = settings.DOJO_BUILD_PROFILE
|
|
else:
|
|
profile_name = args[0]
|
|
profile = self._get_profile(profile_name)
|
|
used_src_version = profile['used_src_version'] % {'DOJO_BUILD_VERSION': settings.DOJO_BUILD_VERSION} # no dependencies to project's settings.py file!
|
|
# used by minify_extreme!
|
|
self.skip_files = profile.get("minify_extreme_skip_files", ())
|
|
self.dojo_base_dir = "%(dojo_root)s/%(version)s" % \
|
|
{'dojo_root':settings.BASE_DOJO_ROOT,
|
|
'version':used_src_version}
|
|
# does the defined dojo-directory exist?
|
|
util_base_dir = "%(dojo_base_dir)s/util" % {'dojo_base_dir':self.dojo_base_dir}
|
|
if not os.path.exists(util_base_dir):
|
|
raise CommandError('Put the the dojo source files (version \'%(version)s\') in the folder \'%(folder)s/%(version)s\' or set a different version in settings.DOJANGO_DOJO_BUILD_VERSION' % \
|
|
{'version':used_src_version,
|
|
'folder':settings.BASE_DOJO_ROOT})
|
|
# check, if java is installed
|
|
try:
|
|
# ignoring output of the java call
|
|
subprocess.call(settings.DOJO_BUILD_JAVA_EXEC, stdout=subprocess.PIPE) # will work with python >= 2.4
|
|
except:
|
|
raise CommandError('Please install java. You need it for building dojo.')
|
|
buildscript_dir = os.path.abspath('%s/buildscripts' % util_base_dir)
|
|
if settings.DOJO_BUILD_USED_VERSION < '1.2.0':
|
|
executable = '%(java_exec)s -jar ../shrinksafe/custom_rhino.jar build.js' % \
|
|
{'java_exec':settings.DOJO_BUILD_JAVA_EXEC}
|
|
else:
|
|
# use the new build command line call!
|
|
if(os.path.sep == "\\"):
|
|
executable = 'build.bat'
|
|
else:
|
|
executable = './build.sh'
|
|
# force executable rights!
|
|
os.chmod(os.path.join(buildscript_dir, 'build.sh'), 0755)
|
|
# use the passed version for building
|
|
version = options.get('build_version', None)
|
|
if not version:
|
|
# if no option --build_version was passed, we use the default build version
|
|
version = profile['build_version'] % {'DOJO_BUILD_VERSION': settings.DOJO_BUILD_VERSION} # no dependencies to project's settings.py file!
|
|
# we add the version to our destination base path
|
|
self.dojo_release_dir = '%(base_path)s/%(version)s' % {
|
|
'base_path':profile['base_root'] % {'BASE_MEDIA_ROOT':settings.BASE_MEDIA_ROOT},
|
|
'version':version} # we don't want to have a dependancy to the project's settings file!
|
|
release_dir = os.path.abspath(os.path.join(self.dojo_release_dir, "../"))
|
|
# the build command handling is so different between the versions!
|
|
# sometimes we need to add /, sometimes not :-(
|
|
if settings.DOJO_BUILD_USED_VERSION < '1.2.0':
|
|
release_dir = release_dir + os.path.sep
|
|
# setting up the build command
|
|
build_addons = ""
|
|
if settings.DOJO_BUILD_USED_VERSION >= '1.2.0':
|
|
# since version 1.2.0 there is an additional commandline option that does the mini build (solved within js!)
|
|
build_addons = "mini=true"
|
|
exe_command = 'cd %(buildscript_dir)s && %(executable)s version=%(version)s releaseName="%(version)s" releaseDir="%(release_dir)s" %(options)s %(build_addons)s' % \
|
|
{'buildscript_dir':buildscript_dir,
|
|
'executable':executable,
|
|
'version':version,
|
|
'release_dir':release_dir,
|
|
'options':profile['options'] % {'BASE_MEDIA_ROOT':settings.BASE_MEDIA_ROOT},
|
|
'build_addons':build_addons}
|
|
# print exe_command
|
|
minify = options['minify']
|
|
minify_extreme = options['minify_extreme']
|
|
prepare_zipserve = options['prepare_zipserve']
|
|
if settings.DOJO_BUILD_USED_VERSION < '1.2.0' and (minify or minify_extreme):
|
|
self._dojo_mini_before_build()
|
|
if sys.platform == 'win32': # fixing issue #39, if dojango is installed on a different drive
|
|
exe_command = os.path.splitdrive(buildscript_dir)[0] + ' && ' + exe_command
|
|
|
|
# do the build
|
|
os.system(exe_command)
|
|
if settings.DOJO_BUILD_USED_VERSION < '1.2.0':
|
|
if minify or minify_extreme:
|
|
self._dojo_mini_after_build()
|
|
if minify_extreme:
|
|
self._dojo_mini_extreme()
|
|
if prepare_zipserve:
|
|
self._dojo_prepare_zipserve()
|
|
|
|
def _get_profile(self, name):
|
|
default_profile_settings = settings.DOJO_BUILD_PROFILES_DEFAULT
|
|
try:
|
|
profile = settings.DOJO_BUILD_PROFILES[name]
|
|
# mixing in the default settings for the build profiles!
|
|
default_profile_settings.update(profile)
|
|
return default_profile_settings
|
|
except KeyError:
|
|
raise CommandError('The profile \'%s\' does not exist in DOJO_BUILD_PROFILES' % name)
|
|
|
|
def _dojo_mini_before_build(self):
|
|
# FIXME: refs #6616 - could be able to set a global copyright file and null out build_release.txt
|
|
shutil.move("%s/util/buildscripts/copyright.txt" % self.dojo_base_dir, "%s/util/buildscripts/_copyright.txt" % self.dojo_base_dir)
|
|
if not os.path.exists("%s/util/buildscripts/copyright_mini.txt" % self.dojo_base_dir):
|
|
f = open("%s/util/buildscripts/copyright.txt" % self.dojo_base_dir, 'w')
|
|
f.write('''/*
|
|
Copyright (c) 2004-2008, The Dojo Foundation All Rights Reserved.
|
|
Available via Academic Free License >= 2.1 OR the modified BSD license.
|
|
see: http://dojotoolkit.org/license for details
|
|
*/''')
|
|
f.close()
|
|
else:
|
|
shutil.copyfile("%s/util/buildscripts/copyright_mini.txt" % self.dojo_base_dir, "%s/util/buildscripts/copyright.txt" % self.dojo_base_dir)
|
|
shutil.move("%s/util/buildscripts/build_notice.txt" % self.dojo_base_dir, "%s/util/buildscripts/_build_notice.txt" % self.dojo_base_dir)
|
|
# create an empty build-notice-file
|
|
f = open("%s/util/buildscripts/build_notice.txt" % self.dojo_base_dir, 'w')
|
|
f.close()
|
|
|
|
def _dojo_mini_after_build(self):
|
|
try:
|
|
'''Copied from the build_mini.sh shell script (thank you Pete Higgins :-))'''
|
|
if not os.path.exists(self.dojo_release_dir):
|
|
raise CommandError('The dojo build failed! Check messages above!')
|
|
else:
|
|
# remove dojox tests and demos - they all follow this convetion
|
|
self._remove_files('%s/dojox' % self.dojo_release_dir, ('^tests$', '^demos$'))
|
|
# removed dijit tests
|
|
dijit_tests = ("dijit/tests", "dijit/demos", "dijit/bench",
|
|
"dojo/tests", "util",
|
|
"dijit/themes/themeTesterImages")
|
|
self._remove_folders(dijit_tests)
|
|
# noir isn't worth including yet
|
|
noir_theme_path = ("%s/dijit/themes/noir" % self.dojo_release_dir,)
|
|
self._remove_folders(noir_theme_path)
|
|
# so the themes are there, lets assume that, piggyback on noir: FIXME later
|
|
self._remove_files('%s/dijit/themes' % self.dojo_release_dir, ('^.*\.html$',))
|
|
self._remove_files(self.dojo_release_dir, ('^.*\.uncompressed\.js$',))
|
|
# WARNING: templates have been inlined into the .js -- if you are using dynamic templates,
|
|
# or other build trickery, these lines might not work!
|
|
self._remove_files("dijit/templates", ("^\.html$",))
|
|
self._remove_files("dijit/form/templates", ("^\.html$",))
|
|
self._remove_files("dijit/layout/templates", ("^\.html$",))
|
|
# .. assume you didn't, and clean up all the README's (leaving LICENSE, mind you)
|
|
self._remove_files('%s/dojo/dojox' % self.dojo_release_dir, ('^README$',))
|
|
dojo_folders = ("dojo/_base",)
|
|
self._remove_folders(dojo_folders)
|
|
os.remove("%s/dojo/_base.js" % self.dojo_release_dir)
|
|
os.remove("%s/dojo/build.txt" % self.dojo_release_dir)
|
|
os.remove("%s/dojo/tests.js" % self.dojo_release_dir)
|
|
except Exception, e:
|
|
print e
|
|
# cleanup from above, refs #6616
|
|
shutil.move("%s/util/buildscripts/_copyright.txt" % self.dojo_base_dir, "%s/util/buildscripts/copyright.txt" % self.dojo_base_dir)
|
|
shutil.move("%s/util/buildscripts/_build_notice.txt" % self.dojo_base_dir, "%s/util/buildscripts/build_notice.txt" % self.dojo_base_dir)
|
|
|
|
def _remove_folders(self, folders):
|
|
for folder in folders:
|
|
if os.path.exists("%s/%s" % (self.dojo_release_dir, folder)):
|
|
shutil.rmtree("%s/%s" % (self.dojo_release_dir, folder))
|
|
|
|
def _remove_files(self, base_folder, regexp_list):
|
|
for root, dirs, files in os.walk(base_folder):
|
|
for file in files:
|
|
# remove all html-files
|
|
for regexp in regexp_list:
|
|
my_re = re.compile(regexp)
|
|
if my_re.match(file):
|
|
os.remove(os.path.join(root, file))
|
|
for dir in dirs:
|
|
for regexp in regexp_list:
|
|
my_re = re.compile(regexp)
|
|
if my_re.match(dir):
|
|
shutil.rmtree(os.path.join(root, dir))
|
|
|
|
SKIP_FILES = (
|
|
'(.*\.png)',
|
|
'(.*\.gif)',
|
|
'(.*\.jpg)',
|
|
'(.*\.svg)',
|
|
'(.*\.swf)',
|
|
'(.*\.fla)',
|
|
'(.*\.mov)',
|
|
'(.*\.smd)',
|
|
'(dojo/_firebug/firebug\..*)',
|
|
'(dojo/dojo\.(xd\.)?js)',
|
|
'(dojo/nls/.*)',
|
|
'(dojo/resources/dojo\.css)',
|
|
'(dojo/resources/blank\.html)',
|
|
'(dojo/resources/iframe_history\.html)',
|
|
'(dijit/themes/tundra/tundra\.css)',
|
|
'(dijit/themes/soria/soria\.css)',
|
|
'(dijit/themes/nihilo/nihilo\.css)',
|
|
'(dojox/dtl/contrib/.*)',
|
|
'(dojox/dtl/ext-dojo/.*)',
|
|
'(dojox/dtl/filter/.*)',
|
|
'(dojox/dtl/render/.*)',
|
|
'(dojox/dtl/tag/.*)',
|
|
'(dojox/dtl/utils/.*)',
|
|
'(dojox/io/proxy/xip_.*\.html)',
|
|
)
|
|
def _dojo_mini_extreme(self):
|
|
"""
|
|
This method removes all js files and just leaves all layer dojo files and static files (like "png", "gif", "svg", "swf", ...)
|
|
"""
|
|
# prepare the regexp of files not to be removed!
|
|
# mixin the profile specific skip files
|
|
skip_files = self.SKIP_FILES + self.skip_files
|
|
my_re = re.compile('^(.*/)?(%s)$' % "|".join(skip_files))
|
|
try:
|
|
'''Copied from the build_mini.sh shell script'''
|
|
if not os.path.exists(self.dojo_release_dir):
|
|
raise CommandError('The dojo build failed! Check messages above!')
|
|
else:
|
|
for root, dirs, files in os.walk(self.dojo_release_dir):
|
|
for file in files:
|
|
# remove all html-files
|
|
my_file = os.path.abspath(os.path.join(root, file))
|
|
if not my_re.match(my_file):
|
|
os.remove(my_file)
|
|
# now remove all empty directories
|
|
for root, dirs, files in os.walk(self.dojo_release_dir):
|
|
for dir in dirs:
|
|
try:
|
|
# just empty directories will be removed!
|
|
os.removedirs(os.path.join(root, dir))
|
|
except OSError:
|
|
pass
|
|
except Exception, e:
|
|
print e
|
|
|
|
DOJO_ZIP_SPECIAL = {'dojox': ['form', 'widget', 'grid']} # these modules will be zipped separately
|
|
def _dojo_prepare_zipserve(self):
|
|
"""
|
|
Creates zip packages for each dojo module within the current release folder.
|
|
It splits the module dojox into several modules, so it fits the 1000 files limit of
|
|
Google AppEngine.
|
|
"""
|
|
for folder in os.listdir(self.dojo_release_dir):
|
|
module_dir = '%s/%s' % (self.dojo_release_dir, folder)
|
|
if os.path.isdir(module_dir):
|
|
if folder in self.DOJO_ZIP_SPECIAL.keys():
|
|
for special_module in self.DOJO_ZIP_SPECIAL[folder]:
|
|
special_module_dir = os.path.join(module_dir, special_module)
|
|
create_zip(special_module_dir,
|
|
'%(base_module)s/%(special_module)s' % {
|
|
'base_module': folder,
|
|
'special_module': special_module
|
|
},
|
|
'%(module_dir)s.%(special_module)s.zip' % {
|
|
'module_dir': module_dir,
|
|
'special_module': special_module
|
|
}
|
|
)
|
|
# remove the whole special module
|
|
shutil.rmtree(special_module_dir)
|
|
# now add the
|
|
create_zip(module_dir, folder, module_dir + ".zip")
|
|
shutil.rmtree(module_dir)
|
|
|
|
|
|
def zipfolder(path, relname, archive):
|
|
paths = os.listdir(path)
|
|
for p in paths:
|
|
p1 = os.path.join(path, p)
|
|
p2 = os.path.join(relname, p)
|
|
if os.path.isdir(p1):
|
|
zipfolder(p1, p2, archive)
|
|
else:
|
|
archive.write(p1, p2)
|
|
|
|
def create_zip(path, relname, archname):
|
|
import zipfile
|
|
archive = zipfile.ZipFile(archname, "w", zipfile.ZIP_DEFLATED)
|
|
if os.path.isdir(path):
|
|
zipfolder(path, relname, archive)
|
|
else:
|
|
archive.write(path, relname)
|
|
archive.close()
|