Browse Source

Merge branch 'master' into contentPlugins

pull/47/head
Louis 11 years ago
parent
commit
4adb5edb4d
  1. 29
      songbook
  2. 45
      songbook_core/build.py
  3. 14
      songbook_core/data/examples/example-all.sb
  4. 8
      songbook_core/data/latex/SongbookUtils.sty
  5. 42
      songbook_core/data/latex/crepbook.sty
  6. 12
      songbook_core/data/templates/default.tex
  7. 48
      songbook_core/data/templates/layout.tex
  8. 1
      songbook_core/data/templates/patacrep.tex
  9. 45
      songbook_core/data/templates/songs.tex
  10. 4
      songbook_core/plastex_songs.py
  11. 16
      songbook_core/songs.py
  12. 18
      songbook_core/templates.py

29
songbook

@ -51,7 +51,7 @@ def argument_parser(args):
Book to compile. Book to compile.
""")) """))
parser.add_argument('--datadir', '-d', nargs=1, type=str, action='store', parser.add_argument('--datadir', '-d', nargs='+', type=str, action='append',
help=textwrap.dedent("""\ help=textwrap.dedent("""\
Data location. Expected (not necessarily required) Data location. Expected (not necessarily required)
subdirectories are 'songs', 'img', 'latex', 'templates'. subdirectories are 'songs', 'img', 'latex', 'templates'.
@ -108,16 +108,23 @@ def main():
LOGGER.error("Error while loading file '{}'.".format(songbook_path)) LOGGER.error("Error while loading file '{}'.".format(songbook_path))
sys.exit(1) sys.exit(1)
# Gathering datadirs
if options.datadir is not None: datadirs = []
songbook['datadir'] = options.datadir[0] if options.datadir:
elif 'datadir' in songbook.keys(): # Command line options
if not os.path.isabs(songbook['datadir']): datadirs += [item[0] for item in options.datadir]
songbook['datadir'] = os.path.join(os.path.dirname(songbook_path), if 'datadir' in songbook:
songbook['datadir'] # .sg file
) if isinstance(songbook['datadir'], basestring):
else: songbook['datadir'] = [songbook['datadir']]
songbook['datadir'] = os.path.dirname(songbook_path) datadirs += [
os.path.join(os.path.dirname(songbook_path), path)
for path in songbook['datadir']
]
if not datadirs:
# Default value
datadirs = [os.path.dirname(songbook_path)]
songbook['datadir'] = datadirs
try: try:
sb_builder = SongbookBuilder(songbook, basename) sb_builder = SongbookBuilder(songbook, basename)

45
songbook_core/build.py

@ -57,9 +57,7 @@ class Songbook(object):
'lang': 'english', 'lang': 'english',
'sort': [u"by", u"album", u"@title"], 'sort': [u"by", u"album", u"@title"],
'content': None, 'content': None,
'datadir': os.path.abspath('.'),
} }
self.songslist = None
self._parse_raw(raw_songbook) self._parse_raw(raw_songbook)
@staticmethod @staticmethod
@ -94,7 +92,7 @@ class Songbook(object):
are stored verbatim in self.config. are stored verbatim in self.config.
""" """
self.config.update(raw_songbook) self.config.update(raw_songbook)
self.config['datadir'] = os.path.abspath(self.config['datadir']) self._set_datadir()
# Compute song list # Compute song list
if self.config['content'] is None: if self.config['content'] is None:
@ -102,11 +100,11 @@ class Songbook(object):
"song", "song",
os.path.relpath( os.path.relpath(
filename, filename,
os.path.join(self.config['datadir'], 'songs'), os.path.join(self.config['datadir'][0], 'songs'),
)) ))
for filename for filename
in recursive_find( in recursive_find(
os.path.join(self.config['datadir'], 'songs'), os.path.join(self.config['datadir'][0], 'songs'),
'*.sg', '*.sg',
) )
] ]
@ -114,7 +112,7 @@ class Songbook(object):
content = self.config["content"] content = self.config["content"]
self.config["content"] = [] self.config["content"] = []
for elem in content: for elem in content:
if isinstance(elem, str) or isinstance(elem, unicode): if isinstance(elem, basestring):
self.config["content"].append(("song", elem)) self.config["content"].append(("song", elem))
elif isinstance(elem, list): elif isinstance(elem, list):
self.config["content"].append((elem[0], elem[1])) self.config["content"].append((elem[0], elem[1]))
@ -129,6 +127,25 @@ class Songbook(object):
if key not in self.config['authwords']: if key not in self.config['authwords']:
self.config['authwords'][key] = value self.config['authwords'][key] = value
def _set_datadir(self):
"""Set the default values for datadir"""
try:
if isinstance(self.config['datadir'], basestring):
self.config['datadir'] = [self.config['datadir']]
except KeyError: # No datadir in the raw_songbook
self.config['datadir'] = [os.path.abspath('.')]
abs_datadir = []
for path in self.config['datadir']:
if os.path.exists(path) and os.path.isdir(path):
abs_datadir.append(os.path.abspath(path))
else:
LOGGER.warning("Ignoring non-existent datadir '{}'.".format(path))
abs_datadir.append(__DATADIR__)
self.config['datadir'] = abs_datadir
def _parse_songs(self): def _parse_songs(self):
"""Parse content included in songbook.""" """Parse content included in songbook."""
self.contentlist = SongbookContent(self.config['datadir']) self.contentlist = SongbookContent(self.config['datadir'])
@ -186,18 +203,7 @@ class SongbookBuilder(object):
return self._called_functions[function] return self._called_functions[function]
def _set_latex(self): def _set_latex(self):
"""Set TEXINPUTS and LaTeX options.""" """Set LaTeX options."""
if not 'TEXINPUTS' in os.environ.keys():
os.environ['TEXINPUTS'] = ''
os.environ['TEXINPUTS'] += os.pathsep + os.path.join(
__DATADIR__,
'latex',
)
os.environ['TEXINPUTS'] += os.pathsep + os.path.join(
self.songbook.config['datadir'],
'latex',
)
if self.unsafe: if self.unsafe:
self._pdflatex_options.append("--shell-escape") self._pdflatex_options.append("--shell-escape")
if not self.interactive: if not self.interactive:
@ -250,7 +256,8 @@ class SongbookBuilder(object):
["pdflatex"] + self._pdflatex_options + [self.basename], ["pdflatex"] + self._pdflatex_options + [self.basename],
stdin=PIPE, stdin=PIPE,
stdout=PIPE, stdout=PIPE,
stderr=PIPE) stderr=PIPE,
env=os.environ)
if not self.interactive: if not self.interactive:
process.stdin.close() process.stdin.close()
log = '' log = ''

14
songbook_core/data/examples/example-all.sb

@ -0,0 +1,14 @@
{
"bookoptions" : [
"importantdiagramonly",
"repeatchords",
"lilypond",
"pictures"
],
"booktype" : "chorded",
"lang" : "french",
"authwords" : {
"sep" : ["and", "et"]
},
"datadir" : "."
}

8
songbook_core/data/latex/SongbookUtils.sty

@ -233,7 +233,13 @@
% On-the-fly compilation of lilypond files % On-the-fly compilation of lilypond files
\iflilypondauto \iflilypondauto
\epstopdfDeclareGraphicsRule{.ly}{pdf}{.pdf}{lilypond --format=pdf --output=\Gin@base\ETE@suffix\space #1} \def\HSizeInPT{\strip@pt\hsize\space pt}
\epstopdfDeclareGraphicsRule{.ly}{pdf}{.pdf}{%
lilypond -e "(set! paper-alist (cons '(\@backslashchar"patasize\@backslashchar" . %
(cons (* \HSizeInPT) (* 1 cm) )) paper-alist))" %
-dpaper-size=\@backslashchar"patasize\@backslashchar" %
--format=pdf --output=\Gin@base\ETE@suffix\space %
#1 }
\AppendGraphicsExtensions{.ly} \AppendGraphicsExtensions{.ly}
\fi \fi

42
songbook_core/data/latex/crepbook.sty

@ -125,6 +125,21 @@
\@getelement{#1} \cr % \@getelement{#1} \cr %
\fi % \fi %
} }
\def\@metainfos{%
\ialign{%
\bf{##} \hfil & ## \hfil \cr % Lines definition
\@insertelement{version} %
\@insertelement{date} %
\@insertelement{author} %
\@insertelement{web} %
\@insertelement{mail} %
}
}
\def\@placepicture[#1, #2]{%
\includegraphics[keepaspectratio=true, #1, #2]{\@picture}
\vskip1em
{\hfil\hbox{\small \@picturecopyright}}
}
\def\@maketitle{ \def\@maketitle{
\def\and{\unskip,\cr&} \def\and{\unskip,\cr&}
@ -139,22 +154,23 @@
{\rule{\textwidth}{1mm}} {\rule{\textwidth}{1mm}}
\end{center} \end{center}
\vfil \vfil
\ialign{ \ifdim \paperwidth < \paperheight
\bf{##} \hfil & ## \hfil \cr % Lines definition \@metainfos
\@insertelement{version} % \vfill
\@insertelement{date} %
\@insertelement{author} %
\@insertelement{web} %
\@insertelement{mail} %
}
\vfil
\begin{center} \begin{center}
\includegraphics[keepaspectratio=true, width=12cm, height=12cm]{\@picture} \@placepicture[width=.8\textwidth, height=.5\textheight]
\vskip1em
{\hfil\hbox{\small \@picturecopyright}}
\end{center} \end{center}
\begin{flushright} \else
\begin{minipage}{.3\textwidth}
\@metainfos
\end{minipage}
\begin{minipage}{.7\textwidth}
\hfill%
\@placepicture[width=\textwidth, height=.6\textheight]
\end{minipage}
\fi
\vfil \vfil
\begin{flushright}
{\hfil\rule{.4\textwidth}{.75pt}\par} {\hfil\rule{.4\textwidth}{.75pt}\par}
\@footer \@footer
\end{flushright} \end{flushright}

12
songbook_core/data/templates/default.tex

@ -21,6 +21,12 @@
(* variables *) (* variables *)
{ {
"classoptions": {"description": {"english": "LaTeX class options", "french": "Options de la classe LaTeX"},
"type": "flag",
"join": ",",
"mandatory": true,
"default": {"default":[]}
},
"title": {"description": {"english": "Title", "french": "Titre"}, "title": {"description": {"english": "Title", "french": "Titre"},
"default": {"english": "Guitar songbook", "french": "Recueil de chansons pour guitare"}, "default": {"english": "Guitar songbook", "french": "Recueil de chansons pour guitare"},
"mandatory":true "mandatory":true
@ -69,6 +75,12 @@
(* extends "songs.tex" *) (* extends "songs.tex" *)
(* set indexes = "titleidx,authidx" *) (* set indexes = "titleidx,authidx" *)
(* block documentclass *)
\documentclass[(* for option in classoptions *)
((option)),
(* endfor *)]{article}
(* endblock *)
(* block songbookpreambule *) (* block songbookpreambule *)
(( super() )) (( super() ))

48
songbook_core/data/templates/layout.tex

@ -26,51 +26,15 @@
%% %%
%% Generated using Songbook <http://www.patacrep.com> %% Generated using Songbook <http://www.patacrep.com>
(* variables *) \makeatletter
{ \def\input@path{(* for dir in datadir *)
"instruments": {"description": {"english": "Instruments", "french": "Instruments"}, {((dir))/latex/} %
"type": "flag", (* endfor *)
"values": {"guitar": {"english": "Guitare", "french": "Guitare"},
"ukulele": {"english": "Ukulele", "french": "Ukulele"}
},
"join": ",",
"mandatory": true,
"default": {"default":["guitar"]}
},
"bookoptions": {"description": {"english": "Options", "french": "Options"},
"type": "flag",
"values": {"diagram": {"english": "Chords diagrams", "french": "Diagrammes d'accords"},
"importantdiagramonly": {"english": "Only importants diagrames", "french": "Diagrammes importants uniquement"},
"lilypond": {"english": "Lilypond music sheets", "french": "Partitions lilypond"},
"pictures": {"english": "Cover pictures", "french": "Couvertures d'albums"},
"tabs": {"english": "Tablatures", "french": "Tablatures"},
"repeatchords": {"english": "Repeat chords", "french": "Répéter les accords"},
"onesongperpage": {"english": "One song per page", "french": "Une chanson par page"}
},
"join": ",",
"mandatory": true,
"default": {"default":["diagram","pictures"]}
},
"booktype": {"description": {"english": "Type", "french": "Type"},
"type": "enum",
"values": {"chorded": {"english": "With guitar chords", "french": "Avec accords de guitare" },
"lyric": {"english": "Lyrics only", "french": "Paroles uniquement"}
},
"default": {"default":"chorded"},
"mandatory": true
},
"mainfontsize": {"description": {"english": "Font Size", "french": "Taille de police"},
"type":"font",
"default":{"default": "10"}
},
"lang": {"description": {"english": "Language", "french": "Langue"},
"default": {"english": "english", "french": "french"}
} }
} \makeatother
(* endvariables *)
(* block documentclass *) (* block documentclass *)
\documentclass[((mainfontsize))pt]{article} \documentclass{article}
(* endblock *) (* endblock *)
(* block songbookpackages *) (* block songbookpackages *)

1
songbook_core/data/templates/patacrep.tex

@ -44,6 +44,7 @@
(* extends "default.tex" *) (* extends "default.tex" *)
(* block songbookpackages *) (* block songbookpackages *)
%! booktype, bookoptions and instruments are defined in "songs.tex"
\usepackage[((booktype)), \usepackage[((booktype)),
(* for option in bookoptions *)((option)), (* for option in bookoptions *)((option)),
(* endfor *) (* endfor *)

45
songbook_core/data/templates/songs.tex

@ -18,6 +18,44 @@
%! The latest version of this program can be obtained from %! The latest version of this program can be obtained from
%! https://github.com/patacrep/ %! https://github.com/patacrep/
(* variables *)
{
"instruments": {"description": {"english": "Instruments", "french": "Instruments"},
"type": "flag",
"values": {"guitar": {"english": "Guitare", "french": "Guitare"},
"ukulele": {"english": "Ukulele", "french": "Ukulele"}
},
"join": ",",
"mandatory": true,
"default": {"default":["guitar"]}
},
"bookoptions": {"description": {"english": "Options", "french": "Options"},
"type": "flag",
"values": {"diagram": {"english": "Chords diagrams", "french": "Diagrammes d'accords"},
"importantdiagramonly": {"english": "Only importants diagrames", "french": "Diagrammes importants uniquement"},
"lilypond": {"english": "Lilypond music sheets", "french": "Partitions lilypond"},
"pictures": {"english": "Cover pictures", "french": "Couvertures d'albums"},
"tabs": {"english": "Tablatures", "french": "Tablatures"},
"repeatchords": {"english": "Repeat chords", "french": "Répéter les accords"},
"onesongperpage": {"english": "One song per page", "french": "Une chanson par page"}
},
"join": ",",
"mandatory": true,
"default": {"default":["diagram","pictures"]}
},
"booktype": {"description": {"english": "Type", "french": "Type"},
"type": "enum",
"values": {"chorded": {"english": "With guitar chords", "french": "Avec accords de guitare" },
"lyric": {"english": "Lyrics only", "french": "Paroles uniquement"}
},
"default": {"default":"chorded"},
"mandatory": true
},
"lang": {"description": {"english": "Language", "french": "Langue"},
"default": {"english": "english", "french": "french"}
}
}
(* endvariables *)
(* extends "layout.tex" *) (* extends "layout.tex" *)
@ -39,10 +77,15 @@
\lang{((lang))} \lang{((lang))}
\usepackage{graphicx} \usepackage{graphicx}
\graphicspath{{((datadir))/img/}} \graphicspath{(* for dir in datadir *)
{((dir))/img/} %
(* endfor *)
}
\makeatletter \makeatletter
\@ifpackageloaded{hyperref}{}{\newcommand{\phantomsection}{}} \@ifpackageloaded{hyperref}{}{\newcommand{\phantomsection}{}}
\@ifpackageloaded{hyperref}{}{\newcommand{\hyperlink}[2]{#2}}
\makeatother \makeatother
(* endblock *) (* endblock *)

4
songbook_core/plastex_songs.py

@ -56,9 +56,7 @@ class beginsong(plasTeX.Command): # pylint: disable=invalid-name,too-many-public
for (key, val) in self.attributes['args'].iteritems(): for (key, val) in self.attributes['args'].iteritems():
if isinstance(val, plasTeX.DOM.Element): if isinstance(val, plasTeX.DOM.Element):
args[key] = process_unbr_spaces(val).textContent.encode('utf-8') args[key] = process_unbr_spaces(val).textContent.encode('utf-8')
elif isinstance(val, unicode): elif isinstance(val, basestring):
args[key] = val.encode('utf-8')
elif isinstance(val, str):
args[key] = val.encode('utf-8') args[key] = val.encode('utf-8')
else: else:
args[key] = unicode(val) args[key] = unicode(val)

16
songbook_core/songs.py

@ -90,11 +90,10 @@ def unprefixed_title(title, prefixes):
class SongbookContent(object): class SongbookContent(object):
"""Manipulation et traitement de liste de chansons""" """Manipulation et traitement de liste de chansons"""
def __init__(self, library): def __init__(self, datadirs):
self._songdir = os.path.join(library, 'songs') self.songdirs = [os.path.join(d, 'songs')
for d in datadirs]
# Sorted list of the content self.content = [] # Sorted list of the content
self.content = []
def append_song(self, filename): def append_song(self, filename):
"""Ajout d'une chanson à la liste """Ajout d'une chanson à la liste
@ -124,12 +123,15 @@ class SongbookContent(object):
if type == "song": if type == "song":
# Add all the songs matching the regex # Add all the songs matching the regex
before = len(self.content) before = len(self.content)
for filename in glob.iglob(os.path.join(self._songdir, elem)): for songdir in self.songdirs:
for filename in glob.iglob(os.path.join(songdir, elem)):
self.append_song(filename) self.append_song(filename)
if len(self.content) > before:
break
if len(self.content) == before: if len(self.content) == before:
# No songs were added # No songs were added
LOGGER.warning( LOGGER.warning(
"Expression '{}' did not match any file".format(regexp) "Expression '{}' did not match any file".format(elem)
) )
else: else:
self.append(type, elem) self.append(type, elem)

18
songbook_core/templates.py

@ -68,25 +68,21 @@ def _escape_tex(value):
class TexRenderer(object): class TexRenderer(object):
"""Render a template to a LaTeX file.""" """Render a template to a LaTeX file."""
def __init__(self, template, datadir, lang): def __init__(self, template, datadirs, lang):
'''Start a new jinja2 environment for .tex creation. '''Start a new jinja2 environment for .tex creation.
Arguments: Arguments:
- template: name of the template to use. - template: name of the template to use.
- datadir: location of the data directory (which max contain - datadirs: list of locations of the data directory
file <datadir>/templates/<template>). (which may contain file <datadir>/templates/<template>).
- lang: main language of songbook. - lang: main language of songbook.
''' '''
self.lang = lang self.lang = lang
# Load templates in filesystem ...
loaders = [FileSystemLoader(os.path.join(datadir, 'templates'))
for datadir in datadirs]
self.texenv = Environment( self.texenv = Environment(
loader=ChoiceLoader([ loader=ChoiceLoader(loaders),
FileSystemLoader(
os.path.join(datadir, 'templates')
),
PackageLoader(
'songbook_core', os.path.join('data', 'templates')
),
]),
extensions=[VariablesExtension], extensions=[VariablesExtension],
) )
self.texenv.block_start_string = '(*' self.texenv.block_start_string = '(*'

Loading…
Cancel
Save