2020-08-05 17:08:33 +02:00
|
|
|
#!/usr/bin/python
|
|
|
|
# -*- coding:utf-8 -*-
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
import re
|
|
|
|
import random
|
|
|
|
import time
|
2020-08-07 11:09:11 +02:00
|
|
|
from os import path, makedirs, listdir
|
2020-08-05 17:08:33 +02:00
|
|
|
from jinja2 import Environment, FileSystemLoader
|
|
|
|
|
|
|
|
LICENSES = {'CC-by-sa-2.0': 'license-cc-by-sa-2.0',
|
|
|
|
}
|
|
|
|
|
|
|
|
TEMPLATES = {
|
|
|
|
'beamer': {'fragment': 'frame.tex',
|
|
|
|
'fragment_pratique': 'frame-pratique.tex',
|
|
|
|
'master': 'main-beamer.tex'},
|
|
|
|
'article': {'fragment': 'fragment.tex',
|
|
|
|
'fragment_pratique': 'fragment-pratique.tex',
|
|
|
|
'master': 'main-article.tex'},
|
|
|
|
'questionnaire': {'fragment': 'fragment.tex',
|
|
|
|
'fragment_pratique': 'fragment-pratique.tex',
|
|
|
|
'master': 'main-questionnaire.tex'}
|
|
|
|
}
|
|
|
|
|
|
|
|
LATEX_SUBS = [(re.compile('_'), '\\_'),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2020-09-04 10:35:58 +02:00
|
|
|
DOCUMENTCLASS_RE = re.compile(r'\\documentclass\{(?P<document_class>.+?)\}')
|
|
|
|
SKBCONFIG_RE = re.compile(r'\\skbconfig\[\n\s*root\s*=\s*(?P<root>.*),\n\s*rep\s*=\s*(?P<rep>.*),\n\s*pub\s*=\s*(?P<pub>.*),\n\s*fig\s*=\s*(?P<fig>.*),\n\s*sli\s*=\s*(?P<sli>.*),\n\s*acr\s*=\s*(?P<acr>.*),\n\s*bib\s*=\s*(?P<bib>.*)\n\s*\]\{skblocal.tex\}', re.M)
|
|
|
|
SKBINPUT_RE = re.compile(r'[^%]\\skbinput\[from=(?P<rep>.*?)(,.*)?\]\{(?P<tex>.*?)\}', re.M)
|
|
|
|
|
2020-08-05 17:08:33 +02:00
|
|
|
def get_unique_name(base):
|
|
|
|
now = time.localtime()
|
|
|
|
year = str(now[0])
|
|
|
|
month = str(now[1]).rjust(2, '0')
|
|
|
|
day = str(now[2]).rjust(2, '0')
|
|
|
|
rand = str(random.randint(0, 100)).rjust(2, '0')
|
|
|
|
return '-'.join([base, year, month, day, rand]).decode('utf-8')
|
|
|
|
|
|
|
|
|
|
|
|
def escape_tex(value):
|
|
|
|
newval = value
|
|
|
|
for pattern, replacement in LATEX_SUBS:
|
|
|
|
newval = pattern.sub(replacement, newval)
|
|
|
|
return newval
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
|
|
|
def init(args):
|
|
|
|
"""
|
|
|
|
init function
|
|
|
|
"""
|
2020-08-07 11:09:11 +02:00
|
|
|
def get_institutes_logos(institutes_list=None):
|
|
|
|
if not institutes_list:
|
|
|
|
return []
|
|
|
|
institutes_logos = []
|
|
|
|
known_logos = {path.splitext(path.basename(l))[0]:l for l in listdir('./figures/logos')}
|
|
|
|
for institute in institutes_list:
|
|
|
|
if institute in known_logos:
|
|
|
|
institutes_logos.append(known_logos[institute])
|
|
|
|
else:
|
|
|
|
print(f'Unknown institute {institute}')
|
|
|
|
print(f'Replacing with missing.png')
|
|
|
|
institutes_logos.append('missing.png')
|
|
|
|
return institutes_logos
|
|
|
|
|
2020-08-05 17:08:33 +02:00
|
|
|
root = '../'
|
|
|
|
if args.directory:
|
|
|
|
root = root + re.sub(r'[\w-]+/?', '../', args.directory)
|
|
|
|
else:
|
|
|
|
root = '../'
|
|
|
|
|
|
|
|
name = args.name
|
|
|
|
if name:
|
|
|
|
if path.splitext(name)[1] == '':
|
|
|
|
name = name + '.tex'
|
|
|
|
else:
|
|
|
|
name = get_unique_name('formation')
|
|
|
|
|
|
|
|
title = args.title
|
|
|
|
if not title:
|
|
|
|
title = 'FIXME'
|
|
|
|
else:
|
|
|
|
title = title
|
|
|
|
|
|
|
|
author = args.author
|
|
|
|
if not author:
|
|
|
|
author = 'Cadoles'
|
|
|
|
else:
|
|
|
|
author = author
|
|
|
|
|
|
|
|
client = args.client
|
|
|
|
if not client:
|
|
|
|
client = 'FIXME'
|
|
|
|
else:
|
|
|
|
client = client
|
|
|
|
|
2020-08-07 11:09:11 +02:00
|
|
|
institutes = get_institutes_logos(args.institutes)
|
|
|
|
logos_count = len(institutes) + 1
|
|
|
|
|
2020-08-05 17:08:33 +02:00
|
|
|
directory = args.directory
|
|
|
|
if not directory:
|
|
|
|
directory = ''
|
|
|
|
|
|
|
|
license = LICENSES.get(args.license, 'license-cc-by-sa-2.0')
|
|
|
|
|
|
|
|
document_class = args.format
|
|
|
|
content = 'sli' if document_class == 'beamer' else 'rep'
|
|
|
|
|
|
|
|
env = {'root': root,
|
|
|
|
'class': document_class,
|
|
|
|
'content': content,
|
|
|
|
'title': title,
|
|
|
|
'author': author,
|
|
|
|
'client': client,
|
2020-08-07 11:09:11 +02:00
|
|
|
'license': license,
|
|
|
|
'institutes': institutes,
|
|
|
|
'logos_count': logos_count}
|
2020-08-05 17:08:33 +02:00
|
|
|
master = TEMPLATES[document_class]['master']
|
|
|
|
master_dir = path.join('presentations', directory)
|
|
|
|
programme_dir = path.join(master_dir, 'programme')
|
|
|
|
resources = [(path.join('presentations', directory), master),
|
|
|
|
(programme_dir, 'contenu.tex'),
|
|
|
|
(programme_dir, 'duree.tex'),
|
|
|
|
(programme_dir, 'evaluation.tex'),
|
|
|
|
(programme_dir, 'moyens.tex'),
|
|
|
|
(programme_dir, 'objectifs.tex'),
|
|
|
|
(programme_dir, 'prerequis.tex'),
|
|
|
|
(programme_dir, 'public.tex'),
|
|
|
|
]
|
|
|
|
#('slides', 'license-cc-by-sa-2.0.tex'),
|
|
|
|
#('slides', 'preambule.tex'),
|
|
|
|
#('slides', 'title.tex')]
|
|
|
|
for directory, template_file in resources:
|
|
|
|
template = jinja_env.get_template(template_file)
|
|
|
|
rendered_template = template.render(**env)
|
|
|
|
if not path.exists(directory):
|
|
|
|
makedirs(directory)
|
|
|
|
template_dest_name = name if template_file == master else template_file
|
|
|
|
with open(path.join(directory, template_dest_name), 'w') as rendered_file:
|
|
|
|
rendered_file.write(rendered_template)
|
|
|
|
|
|
|
|
def update(args):
|
|
|
|
"""
|
|
|
|
update function
|
|
|
|
"""
|
|
|
|
with open(args.master, 'r') as master:
|
|
|
|
tex_master = master.read()
|
2020-09-04 10:35:58 +02:00
|
|
|
tex_class = DOCUMENTCLASS_RE.search(tex_master)
|
|
|
|
tex_skbconfig = SKBCONFIG_RE.search(tex_master)
|
|
|
|
tex_skbinputs = SKBINPUT_RE.finditer(tex_master)
|
2020-08-05 17:08:33 +02:00
|
|
|
fragment = TEMPLATES[tex_class.group('document_class')]['fragment']
|
|
|
|
fragment_pratique = TEMPLATES[tex_class.group('document_class')]['fragment_pratique']
|
|
|
|
|
|
|
|
for skbinput in tex_skbinputs:
|
|
|
|
rep = path.dirname(skbinput.group('tex'))
|
|
|
|
rep = path.join(tex_skbconfig.group(skbinput.group('rep')), rep)
|
|
|
|
tex_name = path.basename(skbinput.group('tex'))
|
|
|
|
basename = '{0}.tex'.format(tex_name)
|
|
|
|
dest = path.join(rep, basename)
|
|
|
|
if not path.isfile(dest):
|
|
|
|
print(dest)
|
|
|
|
if not path.isdir(rep):
|
|
|
|
makedirs(rep)
|
|
|
|
template = jinja_env.get_template(fragment_pratique if tex_name.endswith('-pratique') else fragment)
|
|
|
|
env = {'title': basename, 'subtitle': '',
|
|
|
|
'name': dest}
|
|
|
|
rendered_template = template.render(**env)
|
|
|
|
with open(dest, 'w') as rendered_file:
|
|
|
|
rendered_file.write(rendered_template)
|
|
|
|
|
|
|
|
|
|
|
|
def outline(args):
|
|
|
|
"""
|
|
|
|
outline creation
|
|
|
|
"""
|
2020-09-04 10:35:58 +02:00
|
|
|
part_level = 0
|
|
|
|
section_level = 1
|
|
|
|
subsection_level = 2
|
|
|
|
frametitle_level = 3
|
|
|
|
framesubtitle_level = 4
|
|
|
|
def file_path_from_skbinput(skbinput_re, master, skbconfig):
|
|
|
|
rel_path = path.join(skbconfig.group('root'), skbconfig.group(skbinput_re.group('rep')), skbinput_re.group('tex')) + '.tex'
|
|
|
|
root_path = path.abspath(path.dirname(master))
|
|
|
|
return path.normpath(path.join(root_path, rel_path))
|
|
|
|
|
|
|
|
def reorder_lists(*args):
|
|
|
|
reordered_list = []
|
|
|
|
for l in args:
|
|
|
|
reordered_list.extend(l)
|
|
|
|
reordered_list.sort(key=lambda x: x[0])
|
|
|
|
return reordered_list
|
|
|
|
|
|
|
|
def outline_from_include(include, start, document_class):
|
|
|
|
frametitle_re = re.compile(r'\\frametitle\{(?P<name>.*?)\}')
|
|
|
|
framesubtitle_re = re.compile(r'\\framesubtitle\{(?P<name>.*?)\}')
|
|
|
|
skbheading_re = re.compile(r'\\skbheading\{(?P<name>.*?)\}')
|
|
|
|
with open(include, 'r') as include_fh:
|
|
|
|
content = include_fh.read()
|
|
|
|
if document_class == 'beamer':
|
|
|
|
frametitles = frametitle_re.finditer(content)
|
|
|
|
framesubtitles = framesubtitle_re.finditer(content)
|
|
|
|
frametitles_list = [(ft.start(), frametitle_level, ft.group('name')) for ft in frametitles]
|
|
|
|
framesubtitles_list = [(fs.start(), framesubtitle_level, fs.group('name')) for fs in framesubtitles]
|
|
|
|
frame_list = reorder_lists(frametitles_list, framesubtitles_list)
|
|
|
|
if frame_list:
|
|
|
|
div = int('1{}'.format('0'*len(str(frame_list[-1][0]))))
|
|
|
|
return [(start + f[0]/div, f[1], f[2]) for f in frame_list]
|
|
|
|
else:
|
|
|
|
return []
|
|
|
|
|
2020-09-04 11:01:38 +02:00
|
|
|
def filter_outlines(headers_list, max_level=None):
|
|
|
|
filtered_outlines = []
|
|
|
|
default_max_level = max([hl[1] for hl in headers_list])
|
|
|
|
if not max_level:
|
|
|
|
max_level = default_max_level
|
|
|
|
temp_max_level = default_max_level
|
2020-09-04 11:15:12 +02:00
|
|
|
buffered_header = {l: None for l in range(max_level + 1)}
|
2020-09-04 11:01:38 +02:00
|
|
|
filtered_out = ['Pratique', 'Plan', 'Licence du document']
|
|
|
|
|
|
|
|
for header in headers_list:
|
|
|
|
if header[1] <= min(max_level, default_max_level, temp_max_level):
|
|
|
|
if header[2] in filtered_out:
|
|
|
|
temp_max_level = header[1] + 1
|
|
|
|
continue
|
2020-09-04 11:15:12 +02:00
|
|
|
elif header[2] != buffered_header[header[1]]:
|
|
|
|
buffered_header[header[1]] = header[2]
|
|
|
|
for bf in buffered_header:
|
|
|
|
if bf > header[1]:
|
|
|
|
buffered_header[bf] = None
|
2020-09-04 11:01:38 +02:00
|
|
|
filtered_outlines.append(header)
|
2020-09-04 11:15:12 +02:00
|
|
|
temp_max_level = default_max_level
|
2020-09-04 11:01:38 +02:00
|
|
|
return filtered_outlines
|
|
|
|
|
2020-09-04 10:35:58 +02:00
|
|
|
def outline_format(headers_list):
|
|
|
|
levels = list(set([hl[1] for hl in headers_list]))
|
|
|
|
levels.sort()
|
|
|
|
flattened_levels = {l: levels.index(l) for l in levels}
|
|
|
|
for header in headers_list:
|
|
|
|
print('{}{}'.format('\t' * flattened_levels[header[1]], header[2]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-08-05 17:08:33 +02:00
|
|
|
section_re = re.compile(r'\\section\{(?P<name>.*?)\}')
|
|
|
|
part_re = re.compile(r'\\part\{(?P<name>.*?)}')
|
|
|
|
subsection_re = re.compile(r'\\subsection\{(?P<name>.*?)\}')
|
|
|
|
with open(args.master, 'r') as master_tex:
|
|
|
|
master = master_tex.read()
|
2020-09-04 10:35:58 +02:00
|
|
|
skbconfig = SKBCONFIG_RE.search(master)
|
|
|
|
|
|
|
|
document_class = DOCUMENTCLASS_RE.search(master).group('document_class')
|
2020-08-05 17:08:33 +02:00
|
|
|
parts = part_re.finditer(master)
|
2020-09-04 10:35:58 +02:00
|
|
|
sections = section_re.finditer(master)
|
|
|
|
subsections = subsection_re.finditer(master)
|
|
|
|
includes = SKBINPUT_RE.finditer(master)
|
|
|
|
parts_list = [(part.start(), part_level, part.group('name')) for part in parts]
|
|
|
|
sections_list = [(section.start(), section_level, section.group('name')) for section in sections]
|
|
|
|
includes_list = [element for skbinput in includes for element in outline_from_include(file_path_from_skbinput(skbinput, args.master, skbconfig), skbinput.start(), document_class)]
|
|
|
|
subsections_list = [(subsection.start(), subsection_level, subsection.group('name')) for subsection in subsections]
|
2020-09-04 11:01:38 +02:00
|
|
|
print(outline_format(filter_outlines(reorder_lists(parts_list, sections_list, includes_list, subsections_list))))
|
2020-08-05 17:08:33 +02:00
|
|
|
|
|
|
|
|
|
|
|
jinja_loader = FileSystemLoader('./templates')
|
|
|
|
jinja_env = Environment(loader=jinja_loader,
|
|
|
|
block_start_string='((*',
|
|
|
|
block_end_string='*))',
|
|
|
|
variable_start_string='(((',
|
|
|
|
variable_end_string=')))',
|
|
|
|
comment_start_string='((=',
|
|
|
|
comment_end_string='=))',
|
|
|
|
trim_blocks=True)
|
|
|
|
jinja_env.filters['escape_tex'] = escape_tex
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser(description="Préparation des fichiers tex")
|
|
|
|
subparsers = parser.add_subparsers(help='Aide des sous-commandes')
|
|
|
|
parser_init = subparsers.add_parser('init', help='Initialisation du fichier maître')
|
|
|
|
parser_init.add_argument('-f', '--format', help="Format du document", required=True)
|
|
|
|
parser_init.add_argument('-n', '--name', help="Nom du fichier à créer", required=True)
|
|
|
|
parser_init.add_argument('-a', '--author', help="Auteur de la formation")
|
|
|
|
parser_init.add_argument('-c', '--client', help="Client")
|
|
|
|
parser_init.add_argument('-t', '--title', help="Titre de la formation")
|
|
|
|
parser_init.add_argument('-l', '--license', help="Termes de mise à disposition de la formation")
|
|
|
|
parser_init.add_argument('-d', '--directory', help="Sous-répertoires où créer le fichier", required=True)
|
2020-08-07 11:09:11 +02:00
|
|
|
parser_init.add_argument('-i', '--institutes', nargs='*', help="Instituts dont les logos sont requis")
|
2020-08-05 17:08:33 +02:00
|
|
|
parser_init.set_defaults(func=init)
|
|
|
|
parser_update = subparsers.add_parser('update', help='Mise à jour des fichiers inclus')
|
|
|
|
parser_update.add_argument('-m', '--master', help="Emplacement du fichier maître", required=True)
|
|
|
|
parser_update.set_defaults(func=update)
|
|
|
|
parser_outline = subparsers.add_parser('outline', help="Création du programme à partir du fichier maître")
|
|
|
|
parser_outline.add_argument('-m', '--master', help="Emplacement du fichier maître", required=True)
|
|
|
|
parser_outline.set_defaults(func=outline)
|
|
|
|
args = parser.parse_args()
|
|
|
|
args.func(args)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|