Skip to content
Snippets Groups Projects
buildVersion.py 10.7 KiB
Newer Older
#!/usr/bin/env python
# -*- coding: utf-8 -*-
   NAME
          buildVersion -- helper script to build and tag a plugin_dbui version

    SYNOPSIS
          buildVersion [options] version

    DESCRIPTION
          Helper script to build a version of the plugin_dbui.

          The version identifier should contains alphanumeric characters
          Push version identifier in the javascript library.
          Push version number in the CHANGELOG.
          Build debug and minified version of the javascript library.
          Commit the new version in git and tag it
          Build the web2py plugin file
import optparse
import os
import re
import subprocess
import sys
APP = os.path.basename(os.getcwd())
BUILDDIR = '../plugin_dbui_build'
CHANGELOG = 'static/plugin_dbui/CHANGELOG'
Renaud Le Gac's avatar
Renaud Le Gac committed
DBUI_W2P = 'web2py.plugin.dbui.%s.w2p'
EXTJSSRC = 'static/plugin_extjs/src'
JSBASE = 'static/plugin_dbui/src/App.js'
JSDOC = 'static/plugin_dbui/docs/jsduck'
JSLIBDEBUG = 'static/plugin_dbui/dbui-debug.js'
JSLIBMIN = 'static/plugin_dbui/dbui-min.js'
JSLIBSRC = 'static/plugin_dbui/src'
LE GAC Renaud's avatar
LE GAC Renaud committed
SPHINXDOC = 'static/plugin_dbui/docs/sphinx'
SPHINXSRC = 'docs/api'
NOW = datetime.datetime.now()
PACK_PLUGIN_URL = 'http://localhost:8000/%s/default/pack_plugin' % APP

JSDUCK = os.path.expandvars("$HOME/bin/jsduck")
SENCHA = os.path.expandvars("$HOME/bin/sencha")
SPHINX = '/usr/bin/sphinx-build'
MSG_VERSION = 'Enter the new release: '
def compile():
    """compile the javascript code and generate the debug version
    as well as the minified version of the dbui library.
    The compiler verify that the code complied with the class model
    and order the file in the proper way.
    The minified library can be build in several ways, including
    the Ext JS class required by the applications. In the
    current version, the library contains only the dbui classes and
    the Ext JS ones have to be loaded separately. In that sense
    this command is very similar to the yuicompressor one.
    Several compressor can be used yui, closure compiler, ....
    In the current version, the default yui compressor is used?
    This operation relies on the Sencha Cmd:
    http://www.sencha.com/products/sencha-cmd/download
    The details documantation can be found:
    http://docs.sencha.com/extjs/4.2.2/#!/guide/command
    """
    if not os.path.exists(SENCHA):
        print '\n\tThe application sencha is missing !'
        print '\tSee: http://www.sencha.com/products/sencha-cmd/download'
        print '\tSkip this step.\n'
        return
    # clean previous version
    for el in (JSLIBDEBUG, JSLIBMIN):
        if os.path.exists(el):
            os.remove(el)
            print 'Remove javascript library', el

    # debug version of the javascript library
    print '\nDebug version of the javascript library', JSLIBDEBUG
    cmd = ["sencha", "-sdk", os.path.join(cwd, EXTJSSRC),
           "compile", "-class", os.path.join(cwd, JSLIBSRC),
           "exclude", "--namespace", "Ext",
           "and", "concat", os.path.join(cwd, JSLIBDEBUG)]

    subprocess.call(cmd)

    # Minified version of the javascript library
    print '\nMinified version of the javascript library', JSLIBMIN

    cmd = ["sencha", "-sdk", os.path.join(cwd, EXTJSSRC),
           "compile", "-class", os.path.join(cwd, JSLIBSRC),
           "exclude", "--namespace", "Ext",
           "and", "concat", "--yui", os.path.join(cwd, JSLIBMIN)]
def get_version():
    """Get the current version identifier.
    """
    s = open(JSBASE, 'rb').read()
    m = re.match("(.+    version: ')([\w._-]*)('.+)", s, re.DOTALL)
    return m.group(2)


def git():
    """Commit and tag the current release.
    if not os.path.exists(GIT):
        print '\n\tThe application git is missing !'
        print '\tSkip this step.\n'
        return
    # check tag in git
    fi = tempfile.TemporaryFile()
    subprocess.call(["git", "tag"], stdout=fi)
    fi.seek(0)
    if version in fi.read():
        print "\n\ttag %s already exit in git" % version
        sys.exit(1)
    # release message
    m = "Release version %s" % version
    # Commit the new release in git an tag it
    print 'git add', JSBASE, CHANGELOG
    cmd = ["git", "add", JSBASE, CHANGELOG]
    cmd = ["git", "commit", "-m", m]
    cmd = ["git", "tag", "-a", version, "-m", m]
def jsduck():
    """Generate the JavaScript documentation.
    The HTML files are located in static/plugin_dbui/docs/jsduck
    if not os.path.exists(JSDUCK):
        print '\n\tThe application jsduck is missing !'
        print '\tSkip this step.\n'
        return
    # create the directory
    if not os.path.exists(JSDOC):
        os.makedirs(JSDOC)

    # clean the directory
    cmd = ["rm", "-rf", JSDOC]
    subprocess.call(cmd)

    # run JsDuck
    cmd = ["jsduck", EXTJSSRC, JSLIBSRC, \
           "--output", JSDOC, \
           "--title", "plugin_dbui %s" % get_version(), \
           "--warnings=-all:" + EXTJSSRC]

    subprocess.call(cmd)

    print "JavaScript documentation in", JSDOC


def set_version(version):
    """Set version identifier in CHANGELOG and appbase.js
    print 'Set version in', JSBASE
    # look for a pattern App.version = '0.8.3'; in appbase.js
    # split the the string in 3 parts (pre, version, post)
    m = re.match("(.+    version: ')([\w._-]*)('.+)", s, re.DOTALL)
    if m.group(2) == version:
        print '\n\tVersion "%s" already exists in the appbase.js file !' % version
        rep = raw_input('\tDo you want to continue [n]?')
        if rep not in ('y', 'yes'):
            sys.exit(1)

    # update the version and write a new file
    s = m.group(1) + version + m.group(3)
    fi = open(JSBASE, 'wb')
    fi.write(s)
    fi.close()
    # look for a pattern HEAD in the CHANGELOG
    # split the the string in 2 parts (pre HEAD, post HEAD)
    print 'Set version in', CHANGELOG
    m = re.match("(.+HEAD\n)(.*)", s, re.DOTALL)
    if m == None:
        print '\n\tNo HEAD tag in the CHANGELOG!\n'
        rep = raw_input('\tDo you want to continue [n]?')
        if rep not in ('y', 'yes'):
            sys.exit(1)

    # update the version and edit the CHANGELOG
    s = '%s\n%s (%s)\n%s' % (m.group(1), version, NOW.strftime('%b %Y'), m.group(2))
    fi = open(CHANGELOG, 'wb')
    fi.write(s)
    fi.close()
    subprocess.call(["vim", CHANGELOG])

    fn = "%s~" % CHANGELOG
    if os.path.exists(fn):
        os.remove(fn)
LE GAC Renaud's avatar
LE GAC Renaud committed
def sphinx():
    """Generate the Sphinx documentation.

    """
    if not os.path.exists(SPHINX):
        print '\n\tThe application sphinx is missing !'
        print '\tSkip this step.\n'
        return

    if not os.path.exists(SPHINXSRC):
        print '\nNo sphinx source file !'
        return

    # clean the directory
    cmd = ["rm", "-rf", SPHINXDOC]
    subprocess.call(cmd)

    # generate the HTML version
    cmd = [SPHINX, "-b", "html", SPHINXSRC, SPHINXDOC]
    subprocess.call(cmd)

    print "\nSphinx HTML documentation in", SPHINXDOC, "\n"


def web2py():
    """Produce the binary file for the web2py plugin.
    print '\nBuild the web2py plugin binary file'
    rep = raw_input('Check that the web2py service is running ? Type CR to continue.')
    if rep:
        print '\n\tSkip this step.\n'
        return
    f = urllib.urlopen(PACK_PLUGIN_URL)
    s = f.read()
    fn = DBUI_W2P % get_version().replace('.', '')
    fi = open(fn, 'wb')
    fi.write(s)
    fi.close()
    # move the file to the build directory
    fn_build = os.path.join(BUILDDIR, fn)
    if os.path.exists(fn_build):
        os.remove(fn_build)
    os.rename(fn, fn_build)
    print 'Binary file', fn, 'is created in ', BUILDDIR

    # define script options
    ops = optparse.OptionParser()

    ops.add_option("-a", "--all",
                   action="store_true",
                   dest="all",
                   help="run all steps.")

    ops.add_option("-c", "--compile",
                   action="store_true",
                   dest="compile",
                   help="compile the javascript library using sencha command.")
    ops.add_option("-g", "--git",
                   action="store_true",
                   dest="git",
                   help="commit and tag the current release.")
    ops.add_option("-j", "--jsduck",
                   action="store_true",
                   dest="jsduck",
                   help="generate the JavaScript documentation.")
    ops.add_option("-r", "--release",
                   action="store_true",
                   dest="get",
                   help="get the version of the current release and exit.")

LE GAC Renaud's avatar
LE GAC Renaud committed
    ops.add_option("-s", "--sphinx",
                   action="store_true",
                   dest="sphinx",
                   help="generate sphinx documentation.")

    ops.add_option("-v", "--set_version",
                   dest="set",
                   help="set the version.")

    ops.add_option("-w", "--web2py",
                   action="store_true",
                   dest="web2py",
                   help="pack the web2py plugin.")

    ops.set_defaults(all=False,
LE GAC Renaud's avatar
LE GAC Renaud committed
                     sphinx=False,
    (opt, args) = ops.parse_args()
legac's avatar
legac committed

    print '\nStart buildVersion'
legac's avatar
legac committed
    # standalone action
    if opt.get:
        version = get_version()
        print "\nThe version of the current release is %s\n" % version
legac's avatar
legac committed
        version = (args[0] if args else raw_input(MSG_VERSION))
        set_version(version)
legac's avatar
legac committed
        git()
LE GAC Renaud's avatar
LE GAC Renaud committed
    if opt.sphinx:
        sphinx()

legac's avatar
legac committed
    if opt.web2py:
        jsduck()
legac's avatar
legac committed

    # run all steps
    if opt.all:

        version = get_version()
        print "\nThe version of the current release is %s\n" % version

        version = (args[0] if args else raw_input(MSG_VERSION))
        set_version(version)

        git()
        jsduck()
LE GAC Renaud's avatar
LE GAC Renaud committed
        sphinx()
legac's avatar
legac committed