Fetching contributors…
Cannot retrieve contributors at this time
173 lines (143 sloc) 6.54 KB
# NVDA add-on template SCONSTRUCT file
#Copyright (C) 2012, 2014 Rui Batista <>
#This file is covered by the GNU General Public License.
#See the file COPYING.txt for more details.
import codecs
import gettext
import os
import os.path
import zipfile
import buildVars
def md2html(source, dest):
import markdown
lang = os.path.basename(os.path.dirname(source)).replace('_', '-')
title="{addonSummary} {addonVersion}".format(addonSummary=buildVars.addon_info["addon_summary"], addonVersion=buildVars.addon_info["addon_version"])
headerDic = {
"[[!meta title=\"": "# ",
"\"]]": " #",
with, "r", "utf-8") as f:
mdText =
for k, v in headerDic.iteritems():
mdText = mdText.replace(k, v, 1)
htmlText = markdown.markdown(mdText)
with, "w", "utf-8") as f:
f.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n" +
" \"\">\n" +
"<html xmlns=\"\" xml:lang=\"%s\" lang=\"%s\">\n" % (lang, lang) +
"<head>\n" +
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n" +
"<link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" media=\"screen\"/>\n" +
"<title>%s</title>\n" % title +
def mdTool(env):
lambda target,source,env: md2html(source[0].path, target[0].path),
lambda target,source,env: 'Generating %s'%target[0],
env = Environment(ENV=os.environ, tools=['gettexttool', mdTool])
addonFile = env.File("${addon_name}-${addon_version}.nvda-addon")
def addonGenerator(target, source, env, for_signature):
action = env.Action(lambda target, source, env : createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None,
lambda target, source, env : "Generating Addon %s" % target[0])
return action
def manifestGenerator(target, source, env, for_signature):
action = env.Action(lambda target, source, env : generateManifest(source[0].abspath, target[0].abspath) and None,
lambda target, source, env : "Generating manifest %s" % target[0])
return action
def translatedManifestGenerator(target, source, env, for_signature):
dir = os.path.abspath(os.path.join(os.path.dirname(str(source[0])), ".."))
lang = os.path.basename(dir)
action = env.Action(lambda target, source, env : generateTranslatedManifest(source[1].abspath, lang, target[0].abspath) and None,
lambda target, source, env : "Generating translated manifest %s" % target[0])
return action
env['BUILDERS']['NVDAAddon'] = Builder(generator=addonGenerator)
env['BUILDERS']['NVDAManifest'] = Builder(generator=manifestGenerator)
env['BUILDERS']['NVDATranslatedManifest'] = Builder(generator=translatedManifestGenerator)
def createAddonHelp(dir):
docsDir = os.path.join(dir, "doc")
if os.path.isfile("style.css"):
cssPath = os.path.join(docsDir, "style.css")
cssTarget = env.Command(cssPath, "style.css", Copy("$TARGET", "$SOURCE"))
env.Depends(addon, cssTarget)
if os.path.isfile(""):
readmePath = os.path.join(docsDir, "en", "")
readmeTarget = env.Command(readmePath, "", Copy("$TARGET", "$SOURCE"))
env.Depends(addon, readmeTarget)
def createAddonBundleFromPath(path, dest):
""" Creates a bundle from a directory that contains an addon manifest file."""
basedir = os.path.abspath(path)
with zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED) as z:
# FIXME: the include/exclude feature may or may not be useful. Also python files can be pre-compiled.
for dir, dirnames, filenames in os.walk(basedir):
relativePath = os.path.relpath(dir, basedir)
for filename in filenames:
pathInBundle = os.path.join(relativePath, filename)
absPath = os.path.join(dir, filename)
if pathInBundle not in buildVars.excludedFiles: z.write(absPath, pathInBundle)
return dest
def generateManifest(source, dest):
with, "r", "utf-8") as f:
manifest_template =
manifest = manifest_template.format(**buildVars.addon_info)
with, "w", "utf-8") as f:
def generateTranslatedManifest(source, language, out):
_ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).ugettext
vars = {}
for var in ("addon_summary", "addon_description"):
vars[var] = _(buildVars.addon_info[var])
with, "r", "utf-8") as f:
manifest_template =
result = manifest_template.format(**vars)
with, "w", "utf-8") as f:
def expandGlobs(files):
return [f for pattern in files for f in env.Glob(pattern)]
addon = env.NVDAAddon(addonFile, env.Dir('addon'))
langDirs = [f for f in env.Glob(os.path.join("addon", "locale", "*"))]
#Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated
for dir in langDirs:
poFile = dir.File(os.path.join("LC_MESSAGES", "nvda.po"))
env.Depends(moFile, poFile)
translatedManifest = env.NVDATranslatedManifest(dir.File("manifest.ini"), [moFile, os.path.join("manifest-translated.ini.tpl")])
env.Depends(translatedManifest, [""])
env.Depends(addon, [translatedManifest, moFile])
pythonFiles = expandGlobs(buildVars.pythonSources)
for file in pythonFiles:
env.Depends(addon, file)
#Convert markdown files to html
createAddonHelp("addon") # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager
for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')):
htmlFile = env.markdown(mdFile)
env.Depends(htmlFile, mdFile)
env.Depends(addon, htmlFile)
# Pot target
i18nFiles = expandGlobs(buildVars.i18nSources)
'gettext_package_bugs_address' : '',
'gettext_package_name' : buildVars.addon_info['addon_name'],
'gettext_package_version' : buildVars.addon_info['addon_version']
pot = env.gettextPotFile("${addon_name}.pot", i18nFiles, **gettextvars)
env.Alias('pot', pot)
env.Depends(pot, i18nFiles)
mergePot = env.gettextMergePotFile("${addon_name}-merge.pot", i18nFiles, **gettextvars)
env.Alias('mergePot', mergePot)
env.Depends(mergePot, i18nFiles)
# Generate Manifest path
manifest = env.NVDAManifest(os.path.join("addon", "manifest.ini"), os.path.join("manifest.ini.tpl"))
env.Depends(addon, manifest)