#!/usr/bin/python # -*- coding: utf-8 -*- # import getopt, sys import os.path import glob import re import json def matchRegexp(reg, iterable): return [ m.group(1) for m in (reg.match(l) for l in iterable) if m ] def songslist(songs): directories = set(["img/"] + map(lambda x: "songs/" + os.path.dirname(x), songs)) result = ['\\graphicspath{'] + [ ' {{{0}/}},'.format(d) for d in directories ] + ['}'] + [ '\\input{{songs/{0}}}'.format(s.strip()) for s in songs ] return '\n'.join(result) 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, output): name = output[:-4] # default value template = "ancient.tmpl" songs = [] # parse the songbook data if "template" in sb: template = sb["template"] del sb["template"] if "songs" in sb: songs = sb["songs"] del sb["songs"] parameters = parseTemplate("templates/"+template) # 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))) # output songslist if songs == "all": songs = map(lambda x: x[6:], glob.glob('songs/*/*.sg')) songs.sort() if len(songs) > 0: out.write(formatDefinition('songslist', songslist(songs))) 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) ] f.close() out.write(''.join(content)) out.close() def makeDepend(sb, output): name = output[:-2] dependsPattern = re.compile(r"^[^%]*(?:include|input)\{(.*?)\}") indexPattern = re.compile(r"^[^%]*\\(?:newauthor|new)index\{.*\}\{(.*?)\}") lilypondPattern = re.compile(r"^[^%]*\\(?:lilypond)\{(.*?)\}") # check for deps (in sb data) deps = matchRegexp(dependsPattern, [ v for v in sb.itervalues() if type(v) is not list ]) if sb["songs"] == "all": deps += glob.glob('songs/*/*.sg') else: deps += map(lambda x: "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() # 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: "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." def main(): try: opts, args = getopt.getopt(sys.argv[1:], "hs:o:d", ["help","songbook=","output=","depend"]) except getopt.GetoptError, err: # print help and exit print str(err) usage() sys.exit(2) songbook = None depend = False output = None for o, a in opts: if o in ("-h", "--help"): usage() sys.exit() elif o in ("-s", "--songbook"): songbook = a elif o in ("-d", "--depend"): depend = True elif o in ("-o", "--output"): output = a else: assert False, "unhandled option" if songbook and output: f = open(songbook) sb = json.load(f) f.close() if depend: makeDepend(sb, output) else: makeTexFile(sb, output) if __name__ == '__main__': main()