diff --git a/song.py b/song.py deleted file mode 100644 index d0d5a264..00000000 --- a/song.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# - -import re - -reTitle = re.compile('(?<=beginsong\\{)(.(? other_key: - return 1 - return 0 - -def matchRegexp(reg, iterable): - return [ m.group(1) for m in (reg.match(l) for l in iterable) if m ] - -def unprefixed(title, prefixes): - """Remove the first prefix of the list in the beginning of title (if any). - """ - for prefix in prefixes: - match = re.compile(r"^(%s)\b\s*(.*)$" % prefix).match(title) - if match: - return match.group(2) - return title - -class SongsList: - """Manipulation et traitement de liste de chansons""" - - def __init__(self, library, language): - self._library = library - self._language = language - - # Liste triée des chansons - self.songs = [] - - - def append(self, filename): - """Ajout d'une chanson à la liste - - Effets de bord : analyse syntaxique plus ou moins sommaire du fichier - pour en extraire et traiter certaines information (titre, langue, - album, etc.). - """ - path = os.path.join(self._library, 'songs', filename) - # Exécution de PlasTeX - data = parsetex(path) - - song = Song(path, data['languages'], data['titles'], data['args']) - low, high = 0, len(self.songs) - while low != high: - middle = (low + high) / 2 - if song < self.songs[middle]: - high = middle - else: - low = middle + 1 - self.songs.insert(low, song) - - def append_list(self, filelist): - """Ajoute une liste de chansons à la liste - - L'argument est une liste de chaînes, représentant des noms de fichiers. - """ - for filename in filelist: - self.append(filename) - - def latex(self): - """Renvoie le code LaTeX nécessaire pour intégrer la liste de chansons. - """ - result = [ '\\input{{{0}}}'.format(song.path.replace("\\","/").strip()) for song in self.songs] - result.append('\\selectlanguage{%s}' % self._language) - return '\n'.join(result) - - def languages(self): - """Renvoie la liste des langues utilisées par les chansons""" - return set().union(*[set(song.languages) for song in self.songs]) - -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)) +from songbook.build import buildsongbook -def formatDefinition(name, value): - return '\\set@{name}{{{value}}}\n'.format(name=name, value=value) - -def makeTexFile(sb, library, output): - name = output[:-4] - - # default value - template = "patacrep.tmpl" - 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"] - 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("templates/"+template) - - # compute songslist - if songs == "all": - songs = map(lambda x: x[len(library) + 6:], recursiveFind(os.path.join(library, 'songs'), '*.sg')) - songslist = SongsList(library, sb["lang"]) - songslist.append_list(songs) - - sb["languages"] = ",".join(songslist.languages()) - - # output relevant fields - out = open(output, 'w') - 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*%") - f = open("templates/"+template) - content = [ line for line in f if not commentPattern.match(line) ] - - for index, line in enumerate(content): - if re.compile("getLibraryImgDirectory").search(line): - line = line.replace("\\getLibraryImgDirectory", library + "img/") - content[index] = line - if re.compile("getLibraryLilypondDirectory").search(line): - line = line.replace("\\getLibraryLilypondDirectory", library + "lilypond/") - content[index] = line - - f.close() - out.write(''.join(content)) - - out.close() - -def makeDepend(sb, library, output): - name = output[:-2] - - indexPattern = re.compile(r"^[^%]*\\(?:newauthor|new)index\{.*\}\{(.*?)\}") - lilypondPattern = re.compile(r"^[^%]*\\(?:lilypond)\{(.*?)\}") - - # check for deps (in sb data) - deps = []; - if sb["songs"] == "all": - deps += recursiveFind(os.path.join(library, 'songs'), '*.sg') - else: - deps += map(lambda x: library + "songs/" + x, sb["songs"]) - - # check for lilypond deps (in songs data) if necessary - lilypond = [] - if "bookoptions" in sb and "lilypond" in sb["bookoptions"]: - for filename in deps: - tmpl = open(filename) - lilypond += matchRegexp(lilypondPattern, tmpl) - tmpl.close() - - # check for index (in template file) - if "template" in sb: - filename = sb["template"] - else: - filename = "patacrep.tmpl" - tmpl = open("templates/"+filename) - idx = map(lambda x: x.replace("\getname", name), matchRegexp(indexPattern, tmpl)) - tmpl.close() +import getopt +import json +import locale +import os.path +import sys - # write .d file - out = open(output, 'w') - out.write('{0} {1} : {2}\n'.format(output, name+".tex", ' '.join(deps))) - out.write('{0} : {1}\n'.format(name+".pdf", ' '.join(map(lambda x: x+".sbx",idx)+map(lambda x: library+"lilypond/"+x+".pdf", lilypond)))) - out.write('\t$(LATEX) {0}\n'.format(name+".tex")) - out.write('{0} : {1}\n'.format(' '.join(map(lambda x: x+".sxd",idx)), name+".aux")) - out.close() def usage(): print "No usage information yet." @@ -345,31 +43,12 @@ def main(): assert False, "unhandled option" basename = os.path.basename(sbFile)[:-3] - texFile = basename + ".tex" - pdfFile = basename + ".pdf" - + f = open(sbFile) sb = json.load(f) f.close() - # Make TeX file - makeTexFile(sb, library, texFile) - - # First pdflatex pass - call(["pdflatex", texFile]) - - # Make index - sxdFiles = glob.glob("%s_*.sxd" % basename) - print sxdFiles - 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 - call(["pdflatex", texFile]) + buildsongbook(sb, basename, library) if __name__ == '__main__': main() diff --git a/songbook/__init__.py b/songbook/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools.py b/songbook/authors.py similarity index 93% rename from tools.py rename to songbook/authors.py index 56cb280d..ee3010d9 100644 --- a/tools.py +++ b/songbook/authors.py @@ -1,16 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python # -*- coding: utf-8 -*- -# - -import fnmatch -import os - -def recursiveFind(root_directory, pattern): - matches = [] - for root, dirnames, filenames in os.walk(root_directory): - for filename in fnmatch.filter(filenames, pattern): - matches.append(os.path.join(root, filename)) - return matches def split_author_names(string): """Split author between first and last name. diff --git a/songbook/build.py b/songbook/build.py new file mode 100644 index 00000000..8ba065ea --- /dev/null +++ b/songbook/build.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from subprocess import call +import glob +import json +import os.path +import re + +from songbook.files import recursiveFind +from songbook.index import processSXD +from songbook.songs import Song, SongsList + +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 makeTexFile(sb, library, output): + name = output[:-4] + + # default value + template = "patacrep.tmpl" + 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"] + 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("templates/"+template) + + # compute songslist + if songs == "all": + songs = map(lambda x: x[len(library) + 6:], recursiveFind(os.path.join(library, 'songs'), '*.sg')) + songslist = SongsList(library, sb["lang"]) + songslist.append_list(songs) + + sb["languages"] = ",".join(songslist.languages()) + + # output relevant fields + out = open(output, 'w') + 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*%") + f = open("templates/"+template) + content = [ line for line in f if not commentPattern.match(line) ] + + for index, line in enumerate(content): + if re.compile("getLibraryImgDirectory").search(line): + line = line.replace("\\getLibraryImgDirectory", library + "img/") + content[index] = line + if re.compile("getLibraryLilypondDirectory").search(line): + line = line.replace("\\getLibraryLilypondDirectory", library + "lilypond/") + content[index] = line + + f.close() + out.write(''.join(content)) + + out.close() + +def buildsongbook(sb, basename, library): + """Build a songbook + + Arguments: + - sb: Python representation of the .sb songbook configuration file. + - library: directory containing the "songs" directory, itself containing + songs. + - basename: basename of the songbook to be built. + """ + + texFile = basename + ".tex" + pdfFile = basename + ".pdf" + + # Make TeX file + makeTexFile(sb, library, texFile) + + # First pdflatex pass + call(["pdflatex", texFile]) + + # Make index + sxdFiles = glob.glob("%s_*.sxd" % basename) + print sxdFiles + 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 + call(["pdflatex", texFile]) diff --git a/songbook/files.py b/songbook/files.py new file mode 100644 index 00000000..d708bc49 --- /dev/null +++ b/songbook/files.py @@ -0,0 +1,14 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# + +import fnmatch +import os + +def recursiveFind(root_directory, pattern): + matches = [] + for root, dirnames, filenames in os.walk(root_directory): + for filename in fnmatch.filter(filenames, pattern): + matches.append(os.path.join(root, filename)) + return matches + diff --git a/index.py b/songbook/index.py similarity index 98% rename from index.py rename to songbook/index.py index e6ee884b..4d88d296 100644 --- a/index.py +++ b/songbook/index.py @@ -10,13 +10,13 @@ # from unidecode import unidecode -import sys -import re import locale +import re +import sys import warnings -from tools import processauthors -from utils.plastex import simpleparse +from songbook.authors import processauthors +from songbook.plastex import simpleparse # Pattern set to ignore latex command in title prefix keywordPattern = re.compile(r"^%(\w+)\s?(.*)$") diff --git a/utils/patchedbabel.py b/songbook/plastex-patchedbabel.py similarity index 100% rename from utils/patchedbabel.py rename to songbook/plastex-patchedbabel.py diff --git a/utils/songs.py b/songbook/plastex-songs.py similarity index 100% rename from utils/songs.py rename to songbook/plastex-songs.py diff --git a/utils/plastex.py b/songbook/plastex.py similarity index 67% rename from utils/plastex.py rename to songbook/plastex.py index 664aa7a1..245974c4 100755 --- a/utils/plastex.py +++ b/songbook/plastex.py @@ -4,9 +4,11 @@ from plasTeX.TeX import TeX import codecs import copy +import locale import os import sys + def simpleparse(text): """Parse a simple LaTeX string. """ @@ -24,8 +26,8 @@ class SongParser: tex.disableLogging() tex.ownerDocument.context.loadBaseMacros() sys.path.append(os.path.dirname(__file__)) - tex.ownerDocument.context.loadPackage(tex, "patchedbabel") - tex.ownerDocument.context.loadPackage(tex, "songs") + tex.ownerDocument.context.loadPackage(tex, "plastex-patchedbabel") + tex.ownerDocument.context.loadPackage(tex, "plastex-songs") sys.path.pop() return tex @@ -45,9 +47,23 @@ def parsetex(filename): - titles: la liste des titres ; - args: le dictionnaire des paramètres passés à \\beginsong. """ + # /* BEGIN plasTeX patch + # The following lines, and another line a few lines later, are used to + # circumvent a plasTeX bug. It has been reported, with a patch. + # To see if you can delete those lines, set your LC_TIME locale to French, + # during a month containing diacritics (e.g. Février), and run songbook. If + # no plasTeX bug appears, it is safe to remove those lines. + oldlocale = locale.getlocale() + locale.setlocale(locale.LC_TIME, 'C') + # plasTeX patch END */ + # Analyse syntaxique doc = SongParser.parse(filename) + # /* BEGIN plasTeX patch + locale.setlocale(locale.LC_TIME, "%s.%s" % oldlocale) + # plasTeX patch END */ + # Extraction des données data = { "languages": set(), diff --git a/songbook/songs.py b/songbook/songs.py new file mode 100644 index 00000000..1588981b --- /dev/null +++ b/songbook/songs.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from unidecode import unidecode +import locale +import os.path +import re + +from songbook.authors import processauthors +from songbook.plastex import parsetex + +class Song: + #: Ordre de tri + sort = [] + #: Préfixes à ignorer pour le tri par titres + prefixes = [] + #: Dictionnaire des options pour le traitement des auteurs + authwords = {"after": [], "ignore": [], "sep": []} + + def __init__(self, path, languages, titles, args): + self.titles = titles + self.normalized_titles = [locale.strxfrm(unprefixed_title(unidecode(unicode(title, "utf-8")), self.prefixes)) for title in titles] + self.args = args + self.path = path + self.languages = languages + if "by" in self.args.keys(): + self.normalized_authors = [ + locale.strxfrm(author) + for author + in processauthors(self.args["by"], **self.authwords) + ] + else: + self.normalized_authors = [] + + def __repr__(self): + return repr((self.titles, self.args, self.path)) + + def __cmp__(self, other): + if not isinstance(other, Song): + return NotImplemented + for key in self.sort: + if key == "@title": + self_key = self.normalized_titles + other_key = other.normalized_titles + elif key == "@path": + self_key = locale.strxfrm(self.path) + other_key = locale.strxfrm(other.path) + elif key == "by": + self_key = self.normalized_authors + other_key = other.normalized_authors + else: + self_key = locale.strxfrm(self.args.get(key, "")) + other_key = locale.strxfrm(other.args.get(key, "")) + + if self_key < other_key: + return -1 + elif self_key > other_key: + return 1 + return 0 + +def unprefixed_title(title, prefixes): + """Remove the first prefix of the list in the beginning of title (if any). + """ + for prefix in prefixes: + match = re.compile(r"^(%s)\b\s*(.*)$" % prefix).match(title) + if match: + return match.group(2) + return title + +class SongsList: + """Manipulation et traitement de liste de chansons""" + + def __init__(self, library, language): + self._library = library + self._language = language + + # Liste triée des chansons + self.songs = [] + + + def append(self, filename): + """Ajout d'une chanson à la liste + + Effets de bord : analyse syntaxique plus ou moins sommaire du fichier + pour en extraire et traiter certaines information (titre, langue, + album, etc.). + """ + path = os.path.join(self._library, 'songs', filename) + # Exécution de PlasTeX + data = parsetex(path) + + song = Song(path, data['languages'], data['titles'], data['args']) + low, high = 0, len(self.songs) + while low != high: + middle = (low + high) / 2 + if song < self.songs[middle]: + high = middle + else: + low = middle + 1 + self.songs.insert(low, song) + + def append_list(self, filelist): + """Ajoute une liste de chansons à la liste + + L'argument est une liste de chaînes, représentant des noms de fichiers. + """ + for filename in filelist: + self.append(filename) + + def latex(self): + """Renvoie le code LaTeX nécessaire pour intégrer la liste de chansons. + """ + result = [ '\\input{{{0}}}'.format(song.path.replace("\\","/").strip()) for song in self.songs] + result.append('\\selectlanguage{%s}' % self._language) + return '\n'.join(result) + + def languages(self): + """Renvoie la liste des langues utilisées par les chansons""" + return set().union(*[set(song.languages) for song in self.songs]) diff --git a/songbook/tex.py b/songbook/tex.py new file mode 100644 index 00000000..cdd8ee5f --- /dev/null +++ b/songbook/tex.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import json +import os.path +import re + +from songbook.files import recursiveFind +from songbook.songs import Song, SongsList + +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 makeTexFile(sb, library, output): + name = output[:-4] + + # default value + template = "patacrep.tmpl" + 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"] + 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("templates/"+template) + + # compute songslist + if songs == "all": + songs = map(lambda x: x[len(library) + 6:], recursiveFind(os.path.join(library, 'songs'), '*.sg')) + songslist = SongsList(library, sb["lang"]) + songslist.append_list(songs) + + sb["languages"] = ",".join(songslist.languages()) + + # output relevant fields + out = open(output, 'w') + 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*%") + f = open("templates/"+template) + content = [ line for line in f if not commentPattern.match(line) ] + + for index, line in enumerate(content): + if re.compile("getLibraryImgDirectory").search(line): + line = line.replace("\\getLibraryImgDirectory", library + "img/") + content[index] = line + if re.compile("getLibraryLilypondDirectory").search(line): + line = line.replace("\\getLibraryLilypondDirectory", library + "lilypond/") + content[index] = line + + f.close() + out.write(''.join(content)) + + out.close() +