#!/usr/bin/env python # -*- coding: utf-8 -*- """ NAME build_version -- build and tag a track_publications version SYNOPSIS build_version [options] DESCRIPTION Helper script to build a version of the track_publications. Push version number in the CHANGELOG. EXAMPLES > build_version -h AUTHOR R. Le Gac, renaud.legac@cppm.in2p3.fr Copyright (c) 2012-2015 R. Le Gac """ import argparse import datetime import os import re import sys import tempfile from os.path import join as opj from subprocess import call # constants APP = os.path.basename(os.getcwd()) API = 'api' CHANGELOG = 'static/CHANGELOG' DBUISRC = 'static/plugin_dbui/src' DOCS = 'static/docs' DOCSRC = 'docs' EXTJSSRC = 'static/plugin_extjs/src' JSDOC = opj(DOCS, 'jsduck') JSLIBDEBUG = 'static/%s-debug.js' % APP JSLIBMIN = 'static/%s-min.js' % APP JSLIBSRC = 'static/%s/src' % APP LATEX = 'latex' NOW = datetime.datetime.now() PDF = "pdf" PDFDOC = opj(DOCS, PDF) REFERENCE = 'reference' USER = 'user' # basic commands GIT = '/usr/bin/git' JSDUCK = os.path.expandvars("$HOME/bin/jsduck") PDFLATEX = '/usr/bin/pdflatex' SENCHA = os.path.expandvars("$HOME/lib/Sencha/Cmd/latest/sencha") SPHINX = '/usr/bin/sphinx-build' MSG_RELEASE = 'Enter the new release: ' def build(): """Compile the javascript code and build documentations. """ compile_js() build_html() for doc in (USER,): docsrc = opj(DOCSRC, doc) if os.path.exists(docsrc): build_pdf(doc) def build_html(): """Build HTML documentations. The source files are located in the following directory:: myapp/docs myapp/docs/api myapp/docs/reference myapp/docs/user """ print "Build the HTML documentations..." jsduck() for doc in (API, REFERENCE, USER): docsrc = opj(DOCSRC, doc) if os.path.exists(docsrc): sphinx("-b html", docsrc, opj(DOCS, doc)) def build_pdf(doc): """ Build PDF documentations... Args: doc (str): sub-directory. Possible values are api, reference, user. """ print "Build the PDF documentations..." latexdoc = opj(DOCS, LATEX) # generate the latex sphinx("-b latex", opj(DOCSRC, doc), latexdoc) # the current directory cwd = os.getcwd() # find the name of the tex file os.chdir(latexdoc) filenames = [el for el in os.listdir('.') if el.endswith('.tex')] filename = (filenames[0] if len(filenames) == 1 else None) if not filename: print "\n\tNo latex file !" return # process the latex file twice call([PDFLATEX, filename]) call([PDFLATEX, filename]) # move the pdf file os.chdir(cwd) pdfdir = opj(DOCS, PDF) if not os.path.exists(pdfdir): os.mkdir(pdfdir) fin = filename.replace('.tex', '.pdf') fout = "%s_%s.pdf" % (os.path.splitext(filename)[0], doc) os.rename(opj(latexdoc, fin), opj(pdfdir, fout)) # remove the latex directory call(["rm", "-rf", latexdoc]) print "PDF documentation in", PDFDOC def change_log(): """Commit CHANGELOG. """ print "Commit CHANGELOG..." if not os.path.exists(GIT): print '\n\tThe application git is missing !' print '\tSkip this step.\n' return # Commit modified files print 'git add', CHANGELOG git("add", CHANGELOG) print 'git commit' msg = "Start release %s" % get_version() git("commit -m", msg) def compile_js(): """compile_js the javascript code and generate the debug version as well as the minified version. 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 documentation can be found: http://docs.sencha.com/extjs/4.2.2/#!/guide/command """ print "Compile the javascript code ..." 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 if not os.path.exists(JSLIBSRC): print 'No javascript library. Exit.' return # clean previous version for item in (JSLIBDEBUG, JSLIBMIN): if os.path.exists(item): os.remove(item) print 'Remove old javascript library', item # debug version of the javascript library cmd = ["sencha", "-sdk", EXTJSSRC, "compile", "-classpath", "%s,%s" % (JSLIBSRC, DBUISRC), "exclude", "--namespace", "Ext,App", "and", "concat", JSLIBDEBUG] call(cmd) print 'Debug version of the javascript library', JSLIBDEBUG, 'is ready' # Minified version of the javascript library cmd = ["sencha", "-sdk", EXTJSSRC, "compile", "-classpath", "%s,%s" % (JSLIBSRC, DBUISRC), "exclude", "--namespace", "Ext,App", "and", "concat", "--yui", JSLIBMIN] call(cmd) print 'Minified version of the javascript library', JSLIBMIN, 'is ready' def get_version(): """Get the current version identifier in the CHANGELOG Returns: str: the version number """ log = open(CHANGELOG).read() match = re.search(r"(\d+\.\d+(\.\d+)*)", log) if match: return match.group(1) return "" def git(*args, **kwargs): """run any git instruction: Args: *args: list of variable arguments containing git command and their options **kwargs: keyword argument of the function ``subprocess.call``. Examples: git("add CHANGELOG foo.txt") git("add", CHANGELOG, "foo.txt") git("commit", stdout=fi) """ if not os.path.exists(GIT): print '\n\tThe application git is missing !' print '\tSkip this step.\n' return cmd = [GIT] cmd.extend(args[0].split()) if len(args) > 1: cmd.extend(args[1:]) call(cmd, **kwargs) def jsduck(): """Generate the JavaScript documentation. The HTML files are located in static/plugin_dbui/docs/jsduck """ print "Build the javascript documentation..." if not os.path.exists(JSDUCK): print '\n\tThe application jsduck is missing !' print '\tSkip this step.\n' return if not os.path.exists(JSLIBSRC): print 'No javascript library. Exit.' return # create the directory if not os.path.exists(JSDOC): os.makedirs(JSDOC) # clean the directory cmd = ["rm", "-rf", JSDOC] call(cmd) # run JsDuck cmd = ["jsduck", EXTJSSRC, JSLIBSRC, \ "--output", JSDOC, \ "--title", "plugin_dbui %s" % get_version(), \ "--warnings=-all:" + EXTJSSRC] call(cmd) print "JavaScript documentation in", JSDOC def set_version(version): """Set release identifier in CHANGELOG. Args: version (str): release identifier """ print "Update CHANGELOG with the release", version, "..." # check tag in git fichier = tempfile.TemporaryFile() git("tag", stdout=fichier) fichier.seek(0) if version in fichier.read(): print "\n\tRelease %s already exit in git" % version sys.exit(1) # look for a pattern HEAD in the CHANGELOG # split the the string in 2 parts (pre HEAD, post HEAD) print 'Set release', version, 'in', CHANGELOG txt = open(CHANGELOG, 'rb').read() match = re.match("(.+HEAD\n)(.*)", txt, re.DOTALL) if match == 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 tpl = (match.group(1), version, NOW.strftime('%b %Y'), match.group(2)) txt = '%s\n%s (%s)\n%s' % tpl fichier = open(CHANGELOG, 'wb') fichier.write(txt) fichier.close() call(["vim", CHANGELOG]) # cleaning filename = "%s~" % CHANGELOG if os.path.exists(filename): os.remove(filename) def sphinx(*args, **kwargs): """run the sphinx-build: Args: *args: list of variable arguments containing the sphinx-build options. **kwargs: keyword argument of the function ``subprocess.call``. Examples: sphinx("-b html sourcedir outdir") sphinx("-b html", sourcedir, outdir) """ if not os.path.exists(SPHINX): print '\n\tThe application sphinx is missing !' print '\tSkip this step.\n' return cmd = [SPHINX] cmd.extend(args[0].split()) if len(args) > 1: cmd.extend(args[1:]) call(cmd, **kwargs) def start_release(): """Start the release cycle. """ print "Start the release cycle..." git("checkout", "master") old_release = get_version() print "Current release is", old_release new_release = raw_input(MSG_RELEASE) if not new_release: sys.exit(0) set_version(new_release) change_log() build() if __name__ == '__main__': # define script options APS = argparse.ArgumentParser() APS.add_argument("-a", "--api-doc", action="store_true", help="build the API documentation in HTML.") APS.add_argument("-A", "--api-pdf", action="store_true", help="build the API documentation in PDF.") APS.add_argument("-b", "--build", action="store_true", help="build the javascript library and the documentation.") APS.add_argument("-c", "--compile", action="store_true", help="compile the javascript library.") APS.add_argument("-C", "--commit-changelog", action="store_true", help="commit CHANGELOG. " "To be used with --write-release. " "Recommend to use --start-release.") APS.add_argument("-j", "--jsduck", action="store_true", help="build the JavaScript documentation.") APS.add_argument("-r", "--reference-doc", action="store_true", help="build the reference manual in HTML.") APS.add_argument("-R", "--reference-pdf", action="store_true", help="build the reference manual in PDF.") APS.add_argument("-s", "--start-release", action="store_true", help="start the new release cycle. " "Set the release number in the changelog and " "commit changes in the master branch. " "Equivalent to --write-release followed by " "--commit-changelog.") APS.add_argument("-u", "--user-doc", action="store_true", help="build the user manual in HTML.") APS.add_argument("-U", "--user-pdf", action="store_true", help="build the user manual in PDF.") APS.add_argument("-v", "--version", action="store_true", help="get the current release identifier.") APS.add_argument("-w", "--write-release", action="store_true", help="write the release number in CHANGELOG. " "To be used with --commit-changelog. " "Recommend to use --start-release.") ARGS = APS.parse_args() if ARGS.api_doc: sphinx("-b html", opj(DOCSRC, API), opj(DOCS, API)) if ARGS.api_pdf: build_pdf(API) if ARGS.build: build() if ARGS.compile: compile_js() if ARGS.commit_changelog: change_log() if ARGS.jsduck: jsduck() if ARGS.write_release: set_version(raw_input(MSG_RELEASE)) if ARGS.reference_doc: sphinx("-b html", opj(DOCSRC, REFERENCE), opj(DOCS, REFERENCE)) if ARGS.reference_pdf: build_pdf(REFERENCE) if ARGS.start_release: start_release() if ARGS.user_doc: sphinx("-b html", opj(DOCSRC, USER), opj(DOCS, USER)) if ARGS.user_pdf: build_pdf(USER) if ARGS.version: print "\nThe current release is %s\n" % get_version() sys.exit(0)