#!/usr/bin/env python # -*- coding: utf-8 -*- from subprocess import call import codecs import glob import json import os.path import re import sys from songbook.files import recursiveFind from songbook.index import processSXD from songbook.songs import Song, SongsList from songbook import __SHAREDIR__ def parseTemplate(template): embeddedJsonPattern = re.compile(r"^%%:") f = open(template) code = [ line[3:-1] for line in f if embeddedJsonPattern.match(line) ] f.close() data = json.loads(''.join(code)) parameters = dict() for param in data: parameters[param["name"]] = param return parameters def toValue(parameter, data): if "type" not in parameter: return data elif parameter["type"] == "stringlist": if "join" in parameter: joinText = parameter["join"] else: joinText = '' return joinText.join(data) elif parameter["type"] == "color": return data[1:] elif parameter["type"] == "font": return data+'pt' elif parameter["type"] == "enum": return data elif parameter["type"] == "file": return data elif parameter["type"] == "flag": if "join" in parameter: joinText = parameter["join"] else: joinText = '' return joinText.join(data) def formatDeclaration(name, parameter): value = "" if "default" in parameter: value = parameter["default"] return '\\def\\set@{name}#1{{\\def\\get{name}{{#1}}}}\n'.format(name=name) + formatDefinition(name, toValue(parameter, value)) def formatDefinition(name, value): return '\\set@{name}{{{value}}}\n'.format(name=name, value=value) def clean(basename): generated_extensions = [ "_auth.sbx", "_auth.sxd", ".aux", ".log", ".out", ".sxc", ".tex", "_title.sbx", "_title.sxd", ] for ext in generated_extensions: os.unlink(basename + ext) return True def makeTexFile(sb, output): datadir = sb['datadir'] name = output[:-4] template_dir = os.path.join(datadir, 'templates') songs = [] prefixes_tex = "" prefixes = [] authwords_tex = "" authwords = {"after": ["by"], "ignore": ["unknown"], "sep": ["and"]} # parse the songbook data if "template" in sb: template = sb["template"] del sb["template"] else: template = os.path.join(__SHAREDIR__, "templates", "default.tmpl") if "songs" in sb: songs = sb["songs"] del sb["songs"] if "titleprefixwords" in sb: prefixes = sb["titleprefixwords"] for prefix in sb["titleprefixwords"]: prefixes_tex += "\\titleprefixword{%s}\n" % prefix sb["titleprefixwords"] = prefixes_tex if "authwords" in sb: # Populating default value for key in ["after", "sep", "ignore"]: if key not in sb["authwords"]: sb["authwords"][key] = authwords[key] # Processing authwords values authwords = sb["authwords"] for key in ["after", "sep", "ignore"]: for word in authwords[key]: if key == "after": authwords_tex += "\\auth%sword{%s}\n" % ("by", word) else: authwords_tex += "\\auth%sword{%s}\n" % (key, word) sb["authwords"] = authwords_tex if "after" in authwords: authwords["after"] = [re.compile(r"^.*%s\b(.*)" % after) for after in authwords["after"]] if "sep" in authwords: authwords["sep"] = [" %s" % sep for sep in authwords["sep"]] + [","] authwords["sep"] = [re.compile(r"^(.*)%s (.*)$" % sep) for sep in authwords["sep"] ] if "lang" not in sb: sb["lang"] = "french" if "sort" in sb: sort = sb["sort"] del sb["sort"] else: sort = [u"by", u"album", u"@title"] Song.sort = sort Song.prefixes = prefixes Song.authwords = authwords parameters = parseTemplate(os.path.join(template_dir, template)) # compute songslist if songs == "all": songs = [ os.path.relpath(filename, os.path.join(datadir, 'songs')) for filename in recursiveFind(os.path.join(datadir, 'songs'), '*.sg') ] songslist = SongsList(datadir, sb["lang"]) songslist.append_list(songs) sb["languages"] = ",".join(songslist.languages()) # output relevant fields out = codecs.open(output, 'w', 'utf-8') out.write('%% This file has been automatically generated, do not edit!\n') out.write('\\makeatletter\n') # output automatic parameters out.write(formatDeclaration("name", {"default":name})) out.write(formatDeclaration("songslist", {"type":"stringlist"})) # output template parameter command for name, parameter in parameters.iteritems(): out.write(formatDeclaration(name, parameter)) # output template parameter values for name, value in sb.iteritems(): if name in parameters: out.write(formatDefinition(name, toValue(parameters[name],value))) if len(songs) > 0: out.write(formatDefinition('songslist', songslist.latex())) out.write('\\makeatother\n') # output template commentPattern = re.compile(r"^\s*%") with codecs.open(os.path.join(template_dir, template), 'r', 'utf-8') as f: content = [ line for line in f if not commentPattern.match(line) ] for index, line in enumerate(content): if re.compile("getDataImgDirectory").search(line): if os.path.abspath(os.path.join(datadir, "img")).startswith(os.path.abspath(os.path.dirname(output))): imgdir = os.path.relpath(os.path.join(datadir, "img"), os.path.dirname(output)) else: imgdir = os.path.abspath(os.path.join(datadir, "img")) line = line.replace("\\getDataImgDirectory", ' {%s/} ' % imgdir) content[index] = line out.write(u''.join(content)) out.close() def buildsongbook(sb, basename): """Build a songbook Arguments: - sb: Python representation of the .sb songbook configuration file. - basename: basename of the songbook to be built. """ texFile = basename + ".tex" # Make TeX file makeTexFile(sb, texFile) if not os.environ.has_key('TEXINPUTS'): os.environ['TEXINPUTS'] = '' os.environ['TEXINPUTS'] += os.pathsep + os.path.join(__SHAREDIR__, 'latex') os.environ['TEXINPUTS'] += os.pathsep + os.path.join(sb['datadir'], 'latex') # First pdflatex pass if call(["pdflatex", "--shell-escape", texFile]): sys.exit(1) # Make index sxdFiles = glob.glob("%s_*.sxd" % basename) for sxdFile in sxdFiles: print "processing " + sxdFile idx = processSXD(sxdFile) indexFile = open(sxdFile[:-3]+"sbx", "w") indexFile.write(idx.entriesToStr().encode('utf8')) indexFile.close() # Second pdflatex pass if call(["pdflatex", "--shell-escape", texFile]): sys.exit(1) # Cleaning if not clean(basename): sys.exit(1)