Created
March 9, 2012 10:42
-
-
Save miguelrgonzalez/2006036 to your computer and use it in GitHub Desktop.
play build-module command now accepts an extra parameter to exclude some folders from the final build.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import sys | |
import re | |
import zipfile | |
import urllib2 | |
import shutil | |
import string | |
import imp | |
import time | |
import urllib | |
import yaml | |
from play.utils import * | |
NM = ['new-module', 'nm'] | |
LM = ['list-modules', 'lm'] | |
BM = ['build-module', 'bm'] | |
AM = ['add'] | |
IM = ['install'] | |
COMMANDS = NM + LM + BM + IM + AM | |
HELP = { | |
'new-module': "Create a module", | |
'build-module': "Build and package a module", | |
'list-modules': "List modules available from the central modules repository", | |
'install': "Install a module" | |
} | |
DEFAULT_REPO = 'http://www.playframework.org' | |
def load_module(name): | |
base = os.path.normpath(os.path.dirname(os.path.realpath(sys.argv[0]))) | |
mod_desc = imp.find_module(name, [os.path.join(base, 'framework/pym')]) | |
return imp.load_module(name, mod_desc[0], mod_desc[1], mod_desc[2]) | |
json = load_module('simplejson') | |
repositories = [] | |
def execute(**kargs): | |
global repositories | |
command = kargs.get("command") | |
app = kargs.get("app") | |
args = kargs.get("args") | |
env = kargs.get("env") | |
repositories = get_repositories(env['basedir']) | |
if command in NM: | |
new(app, args, env) | |
elif command in LM: | |
list(app, args) | |
elif command in BM: | |
build(app, args, env) | |
elif command in IM: | |
install(app, args, env) | |
elif command in AM: | |
add(app, args, env) | |
def get_repositories(play_base): | |
repopath = os.path.join(play_base, 'repositories') | |
if os.path.exists(repopath): | |
repos = [] | |
f = file(repopath) | |
for line in f: | |
if not re.match("^\s*#", line) and not line.strip() == "": | |
repos.append(line.strip()) | |
if len(repos) > 0: | |
return repos | |
return [DEFAULT_REPO] | |
class Downloader(object): | |
before = .0 | |
history = [] | |
cycles = 0 | |
average = lambda self: sum(self.history) / (len(self.history) or 1) | |
def __init__(self, width=55): | |
self.width = width | |
self.kibi = lambda bits: bits / 2 ** 10 | |
self.proc = lambda a, b: a / (b * 0.01) | |
def retrieve(self, url, destination, callback=None): | |
self.size = 0 | |
time.clock() | |
try: urllib.urlretrieve(url, destination, self.progress) | |
except KeyboardInterrupt: | |
print '\n~ Download cancelled' | |
print '~' | |
for i in range(5): | |
try: | |
os.remove(destination) | |
break | |
except: | |
time.sleep(.1) | |
else: raise | |
if callback: callback() | |
sys.exit() | |
print '' | |
return self.size | |
def progress(self, blocks, blocksize, filesize): | |
self.cycles += 1 | |
bits = min(blocks*blocksize, filesize) | |
if bits != filesize: | |
done = self.proc(bits, filesize) | |
else: | |
done = 100 | |
bar = self.bar(done) | |
if not self.cycles % 3 and bits != filesize: | |
now = time.clock() | |
elapsed = now-self.before | |
if elapsed: | |
speed = self.kibi(blocksize * 3 / elapsed) | |
self.history.append(speed) | |
self.history = self.history[-4:] | |
self.before = now | |
average = round(sum(self.history[-4:]) / 4, 1) | |
self.size = self.kibi(bits) | |
print '\r~ [%s] %s KiB/s ' % (bar, str(average)), | |
def bar(self, done): | |
span = self.width * done * 0.01 | |
offset = len(str(int(done))) - .99 | |
result = ('%d%%' % (done,)).center(self.width) | |
return result.replace(' ', '-', int(span - offset)) | |
class Unzip: | |
def __init__(self, verbose = False, percent = 10): | |
self.verbose = verbose | |
self.percent = percent | |
def extract(self, file, dir): | |
if not dir.endswith(':') and not os.path.exists(dir): | |
os.mkdir(dir) | |
zf = zipfile.ZipFile(file) | |
# create directory structure to house files | |
self._createstructure(file, dir) | |
num_files = len(zf.namelist()) | |
percent = self.percent | |
divisions = 100 / percent | |
perc = int(num_files / divisions) | |
# extract files to directory structure | |
for i, name in enumerate(zf.namelist()): | |
if self.verbose == True: | |
print "Extracting %s" % name | |
elif perc > 0 and (i % perc) == 0 and i > 0: | |
complete = int (i / perc) * percent | |
if not name.endswith('/'): | |
outfile = open(os.path.join(dir, name), 'wb') | |
outfile.write(zf.read(name)) | |
outfile.flush() | |
outfile.close() | |
def _createstructure(self, file, dir): | |
self._makedirs(self._listdirs(file), dir) | |
def _makedirs(self, directories, basedir): | |
""" Create any directories that don't currently exist """ | |
for dir in directories: | |
curdir = os.path.join(basedir, dir) | |
if not os.path.exists(curdir): | |
os.makedirs(curdir) | |
def _listdirs(self, file): | |
""" Grabs all the directories in the zip structure | |
This is necessary to create the structure before trying | |
to extract the file to it. """ | |
zf = zipfile.ZipFile(file) | |
dirs = [] | |
for name in zf.namelist(): | |
dn = os.path.dirname(name) | |
dirs.append(dn) | |
dirs.sort() | |
return dirs | |
def new(app, args, play_env): | |
if os.path.exists(app.path): | |
print "~ Oops. %s already exists" % app.path | |
print "~" | |
sys.exit(-1) | |
print "~ The new module will be created in %s" % os.path.normpath(app.path) | |
print "~" | |
application_name = os.path.basename(app.path) | |
copy_directory(os.path.join(play_env["basedir"], 'resources/module-skel'), app.path) | |
# check_application() | |
replaceAll(os.path.join(app.path, 'build.xml'), r'%MODULE%', application_name) | |
replaceAll(os.path.join(app.path, 'commands.py'), r'%MODULE%', application_name) | |
replaceAll(os.path.join(app.path, 'conf/messages'), r'%MODULE%', application_name) | |
replaceAll(os.path.join(app.path, 'conf/dependencies.yml'), r'%MODULE%', application_name) | |
replaceAll(os.path.join(app.path, 'conf/routes'), r'%MODULE%', application_name) | |
replaceAll(os.path.join(app.path, 'conf/routes'), r'%MODULE_LOWERCASE%', string.lower(application_name)) | |
os.mkdir(os.path.join(app.path, 'app')) | |
os.mkdir(os.path.join(app.path, 'app/controllers')) | |
os.mkdir(os.path.join(app.path, 'app/controllers/%s' % application_name)) | |
os.mkdir(os.path.join(app.path, 'app/models')) | |
os.mkdir(os.path.join(app.path, 'app/models/%s' % application_name)) | |
os.mkdir(os.path.join(app.path, 'app/views')) | |
os.mkdir(os.path.join(app.path, 'app/views/%s' % application_name)) | |
os.mkdir(os.path.join(app.path, 'app/views/tags')) | |
os.mkdir(os.path.join(app.path, 'app/views/tags/%s' % application_name)) | |
os.mkdir(os.path.join(app.path, 'src/play')) | |
os.mkdir(os.path.join(app.path, 'src/play/modules')) | |
os.mkdir(os.path.join(app.path, 'src/play/modules/%s' % application_name)) | |
print "~ OK, the module is created." | |
print "~ Start using it by adding this line in the application.conf modules list: " | |
print "~ module.%s=%s" % (application_name, os.path.normpath(app.path)) | |
print "~" | |
print "~ Have fun!" | |
print "~" | |
def list(app, args): | |
print "~ You can also browse this list online at:" | |
for repo in repositories: | |
print "~ %s/modules" % repo | |
print "~" | |
modules_list = load_module_list() | |
for mod in modules_list: | |
print "~ [%s]" % mod['name'] | |
print "~ %s" % mod['fullname'] | |
print "~ %s/modules/%s" % (mod['server'], mod['name']) | |
vl = '' | |
i = 0 | |
for v in mod['versions']: | |
vl += v["version"] | |
i = i+1 | |
if i < len(mod['versions']): | |
vl += ', ' | |
if vl: | |
print "~ Versions: %s" % vl | |
else: | |
print "~ (No versions released yet)" | |
print "~" | |
print "~ To install one of these modules use:" | |
print "~ play install module-version (eg: play install scala-1.0)" | |
print "~" | |
print "~ Or you can just install the default release of a module using:" | |
print "~ play install module (eg: play install scala)" | |
print "~" | |
def build(app, args, env): | |
ftb = env["basedir"] | |
version = None | |
fwkMatch = None | |
exclude_folders = [] | |
try: | |
optlist, args = getopt.getopt(args, '', ['framework=', 'version=', 'require=','exclude=']) | |
for o, a in optlist: | |
if o in ('--framework'): | |
ftb = a | |
if o in ('--version'): | |
version = a | |
if o in ('--require'): | |
fwkMatch = a | |
if o in ('--exclude'): | |
exclude_folders = [os.path.join(app.path, a) for a in a.split(',')] | |
except getopt.GetoptError, err: | |
print "~ %s" % str(err) | |
print "~ " | |
sys.exit(-1) | |
print exclude_folders | |
deps_file = os.path.join(app.path, 'conf', 'dependencies.yml') | |
if os.path.exists(deps_file): | |
f = open(deps_file) | |
deps = yaml.load(f.read()) | |
versionCandidate = deps["self"].split(" ").pop() | |
version = versionCandidate | |
for dep in deps["require"]: | |
if isinstance(dep, basestring): | |
splitted = dep.split(" ") | |
if len(splitted) == 2 and splitted[0] == "play": | |
fwkMatch = splitted[1] | |
f.close | |
if version is None: | |
version = raw_input("~ What is the module version number? ") | |
if fwkMatch is None: | |
fwkMatch = raw_input("~ What are the playframework versions required? ") | |
build_file = os.path.join(app.path, 'build.xml') | |
if os.path.exists(build_file): | |
print "~" | |
print "~ Building..." | |
print "~" | |
os.system('ant -f %s -Dplay.path=%s' % (build_file, ftb) ) | |
print "~" | |
mv = '%s-%s' % (os.path.basename(app.path), version) | |
print("~ Packaging %s ... " % mv) | |
dist_dir = os.path.join(app.path, 'dist') | |
if os.path.exists(dist_dir): | |
shutil.rmtree(dist_dir) | |
os.mkdir(dist_dir) | |
manifest = os.path.join(app.path, 'manifest') | |
manifestF = open(manifest, 'w') | |
manifestF.write('version=%s\nframeworkVersions=%s\n' % (version, fwkMatch)) | |
manifestF.close() | |
zip = zipfile.ZipFile(os.path.join(dist_dir, '%s.zip' % mv), 'w', zipfile.ZIP_STORED) | |
for (dirpath, dirnames, filenames) in os.walk(app.path): | |
if filter(lambda x: dirpath.startswith(x), exclude_folders): | |
print "~ Excluding folder %s from build" % dirpath | |
continue | |
if dirpath == dist_dir: | |
continue | |
if dirpath.find(os.sep + '.') > -1 or dirpath.find('/tmp/') > -1 or dirpath.find('/test-result/') > -1 or dirpath.find('/logs/') > -1 or dirpath.find('/eclipse/') > -1 or dirpath.endswith('/test-result') or dirpath.endswith('/logs') or dirpath.endswith('/eclipse') or dirpath.endswith('/nbproject'): | |
continue | |
for file in filenames: | |
if file.find('~') > -1 or file.endswith('.iml') or file.startswith('.'): | |
continue | |
zip.write(os.path.join(dirpath, file), os.path.join(dirpath[len(app.path):], file)) | |
zip.close() | |
os.remove(manifest) | |
print "~" | |
print "~ Done!" | |
print "~ Package is available at %s" % os.path.join(dist_dir, '%s.zip' % mv) | |
print "~" | |
def install(app, args, env): | |
if len(sys.argv) < 3: | |
help_file = os.path.join(env["basedir"], 'documentation/commands/cmd-install.txt') | |
print open(help_file, 'r').read() | |
sys.exit(0) | |
name = cmd = sys.argv[2] | |
groups = re.match(r'^([a-zA-Z0-9]+)([-](.*))?$', name) | |
module = groups.group(1) | |
version = groups.group(3) | |
modules_list = load_module_list() | |
fetch = None | |
for mod in modules_list: | |
if mod['name'] == module: | |
for v in mod['versions']: | |
if version is None and v['isDefault']: | |
print '~ Will install %s-%s' % (module, v['version']) | |
print '~ This module is compatible with: %s' % v['matches'] | |
ok = raw_input('~ Do you want to install this version (y/n)? ') | |
if not ok == 'y': | |
print '~' | |
sys.exit(-1) | |
print '~ Installing module %s-%s...' % (module, v['version']) | |
fetch = '%s/modules/%s-%s.zip' % (mod['server'], module, v['version']) | |
break | |
if version == v['version']: | |
print '~ Will install %s-%s' % (module, v['version']) | |
print '~ This module is compatible with: %s' % v['matches'] | |
ok = raw_input('~ Do you want to install this version (y/n)? ') | |
if not ok == 'y': | |
print '~' | |
sys.exit(-1) | |
print '~ Installing module %s-%s...' % (module, v['version']) | |
fetch = '%s/modules/%s-%s.zip' % (mod['server'], module, v['version']) | |
break | |
if fetch is None: | |
print '~ No module found \'%s\'' % name | |
print '~ Try play list-modules to get the modules list' | |
print '~' | |
sys.exit(-1) | |
archive = os.path.join(env["basedir"], 'modules/%s-%s.zip' % (module, v['version'])) | |
if os.path.exists(archive): | |
os.remove(archive) | |
print '~' | |
print '~ Fetching %s' % fetch | |
Downloader().retrieve(fetch, archive) | |
if not os.path.exists(archive): | |
print '~ Oops, file does not exist' | |
print '~' | |
sys.exist(-1) | |
print '~ Unzipping...' | |
if os.path.exists(os.path.join(env["basedir"], 'modules/%s-%s' % (module, v['version']))): | |
shutil.rmtree(os.path.join(env["basedir"], 'modules/%s-%s' % (module, v['version']))) | |
os.mkdir(os.path.join(env["basedir"], 'modules/%s-%s' % (module, v['version']))) | |
Unzip().extract(archive, os.path.join(env["basedir"], 'modules/%s-%s' % (module, v['version']))) | |
os.remove(archive) | |
print '~' | |
print '~ Module %s-%s is installed!' % (module, v['version']) | |
print '~ You can now use it by adding it to the dependencies.yml file:' | |
print '~' | |
print '~ require:' | |
print '~ play -> %s %s' % (module, v['version']) | |
print '~' | |
sys.exit(0) | |
def add(app, args, env): | |
app.check() | |
m = None | |
try: | |
optlist, args = getopt.getopt(args, '', ['module=']) | |
for o, a in optlist: | |
if o in ('--module'): | |
m = a | |
except getopt.GetoptError, err: | |
print "~ %s" % str(err) | |
print "~ " | |
sys.exit(-1) | |
if m is None: | |
print "~ Usage: play add --module=<modulename>" | |
print "~ " | |
sys.exit(-1) | |
appConf = os.path.join(app.path, 'conf/application.conf') | |
if not fileHas(appConf, '# ---- MODULES ----'): | |
print "~ Line '---- MODULES ----' missing in your application.conf. Add it to use this command." | |
print "~ " | |
sys.exit(-1) | |
mn = m | |
if mn.find('-') > 0: | |
mn = mn[:mn.find('-')] | |
if mn in app.module_names(): | |
print "~ Module %s already declared in application.conf, not doing anything." % mn | |
print "~ " | |
sys.exit(-1) | |
replaceAll(appConf, r'# ---- MODULES ----', '# ---- MODULES ----\nmodule.%s=${play.path}/modules/%s' % (mn, m) ) | |
print "~ Module %s add to application %s." % (mn, app.name()) | |
print "~ " | |
def load_module_list(): | |
def addServer(module, server): | |
module['server'] = server | |
return module | |
def any(arr, func): | |
for x in arr: | |
if func(x): return True | |
return False | |
modules = None | |
rev = repositories[:] # clone | |
rev.reverse() | |
for repo in rev: | |
result = load_modules_from(repo) | |
if modules is None: | |
modules = map(lambda m: addServer(m, repo), result['modules']) | |
else: | |
for module in result['modules']: | |
if not any(modules, lambda m: m['name'] == module['name']): | |
modules.append(addServer(module, repo)) | |
return modules | |
def load_modules_from(modules_server): | |
try: | |
url = '%s/modules' % modules_server | |
req = urllib2.Request(url) | |
req.add_header('Accept', 'application/json') | |
result = urllib2.urlopen(req) | |
return json.loads(result.read()) | |
except urllib2.HTTPError, e: | |
print "~ Oops," | |
print "~ Cannot fetch the modules list from %s (%s)..." % (url, e.code) | |
print "~" | |
sys.exit(-1) | |
except urllib2.URLError, e: | |
print "~ Oops," | |
print "~ Cannot fetch the modules list from %s ..." % (url) | |
print "~" | |
sys.exit(-1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment