From c9e9bf2d688954c7b957cb83ac4427a724cd2ebf Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 2 Mar 2008 19:57:11 +0000 Subject: [PATCH] Switch help generation system to use Genshi templates --- src/libprs500/manual/about.txt | 1 - src/libprs500/manual/images/valid.png | Bin 2037 -> 2026 bytes src/libprs500/manual/libprs500.qhp | 109 ------- src/libprs500/manual/libprs500.webprj | 35 -- src/libprs500/manual/make.py | 299 ++++++------------ src/libprs500/manual/templates/about.txt | 1 + .../{libprs500.qhcp => templates/app.qhcp} | 18 +- src/libprs500/manual/templates/app.qhp | 30 ++ src/libprs500/manual/templates/cli-cmd.html | 47 +++ src/libprs500/manual/templates/cli-index.html | 38 +++ src/libprs500/manual/{ => templates}/faq.html | 75 ++--- src/libprs500/manual/{ => templates}/gui.html | 52 ++- .../manual/{ => templates}/index.html | 8 +- src/libprs500/manual/templates/layout.html | 38 +++ src/libprs500/manual/templates/navtree.html | 54 ++-- src/libprs500/manual/templates/news.html | 28 ++ .../manual/{ => templates}/start.html | 39 +-- upload.py | 7 +- 18 files changed, 406 insertions(+), 473 deletions(-) delete mode 100644 src/libprs500/manual/about.txt delete mode 100644 src/libprs500/manual/libprs500.qhp delete mode 100644 src/libprs500/manual/libprs500.webprj create mode 100644 src/libprs500/manual/templates/about.txt rename src/libprs500/manual/{libprs500.qhcp => templates/app.qhcp} (54%) create mode 100644 src/libprs500/manual/templates/app.qhp create mode 100644 src/libprs500/manual/templates/cli-cmd.html create mode 100644 src/libprs500/manual/templates/cli-index.html rename src/libprs500/manual/{ => templates}/faq.html (52%) rename src/libprs500/manual/{ => templates}/gui.html (90%) rename src/libprs500/manual/{ => templates}/index.html (62%) create mode 100644 src/libprs500/manual/templates/layout.html create mode 100644 src/libprs500/manual/templates/news.html rename src/libprs500/manual/{ => templates}/start.html (50%) diff --git a/src/libprs500/manual/about.txt b/src/libprs500/manual/about.txt deleted file mode 100644 index d56c56feba..0000000000 --- a/src/libprs500/manual/about.txt +++ /dev/null @@ -1 +0,0 @@ -libprs500 is an ebook management application with support for various ebook readers. Created by Kovid Goyal © 2007. diff --git a/src/libprs500/manual/images/valid.png b/src/libprs500/manual/images/valid.png index 88fefcbf1c943b78a1abcfde2b47fdd50cbcfb22..e971248a30882777c64eb7695abfb781a1cfac40 100644 GIT binary patch delta 1369 zcmV-f1*ZD-59$w)Dt`e12M7rY3kwYo5E2v>6BZa38XX)Q92y=W93UejBO@RsDI+N@ zC@3fg^_rQmXYimCxe57iH??+mzS8Bn1GX^g_);@ny8SM zpo^fdjiRxcp{kLmwv?*6lQ97?P{7io!`rFC)T+kWt;yZ6%H6Wf;I`1?!otGL%*@o( z)Y#bAz}Dx++UU*S?9=1!-Rbh@=jZI~?BeY6>GAgN^!W4h^YZul_4xb#{{GC&%(Jlp zUjYbrin<>F004`VF$0B@Py-1C0ENR9?~}U&B!2_!Nklw5GLiS6jqb-`L$u3~J3QEe%!z))-oJh!H1Ns;^Ek6= z1U7P&La;(yG(I#i8L{vd5!C}Oz$V%msG`llORcBKow$Hm`0R7-fr~6e>BLmm=Julq2K>85KPqMsVa9$18}Vw5crScym=;!z%-R1r$W(Bk5v zATU6yDpHt*Er7Jvt5DE~DcHxY8w|GeBx2lm&eSMkbq>LP#G@2u*pjYE(Kdp=03v(f z96ovuWtt|Ns*;_Bg7X78Ke zD&!ieEQi7YMV-q4%r^ABHkdZgbhUSQgGiV*Z#T2of8R8#$^#!lT0#CKIlTox()E5C zxc;*Pj65EMDb+DPeE5wf*YCVJ%!AZ7z^e?cS0EqkJSkfMLRVfp+ge;7Tz>-ivVqkA zaAdAIOm%{tFk|ap3Y_!Iig%#-+_P@34}K1ClUfjd&`ogmmFFEFQ&mW3a?A%`V&9Fk zjR057LaN-wZ4IF;{9#(Kte-8LR4hF8$XA|HRp6>mJ+M&2XSvNj>3aU;rj!dF_M?vJ zmWKn=f-lf3997d$ZCw1DxPR7P-sbsWRb%Hwg?-TGu6Vq{O>;`#y4V4hGi3L^*7_s^ zNubu-8B8SJWp{NaSgO#laM*{z3`1MVrLKA0*fb}cY5K)VCX+uwXE!l8^4PBmZopSR z7IMsTequidbG*>zmirs@G=oqf8DUC3uq-xI308$zZgKm5gVgV=uYWIX$Ope6$GN?@ z-BrKKKDXa@o_uXfH1!K|Q>Ff2rc#{(maEBBN%8()ru;N8FO@irr~dy5HTNmV3i>po zcqjPDsd{{$beGK9{kGQbk@3E1+3&CW;8-FSo0ynr9f?@?*=P)p@mNz)-x&{BPl?!w b0sjjsTSX2H16&vY015yANkvXXu0mjfyep-S delta 1363 zcmV-Z1+4n&5A_d_Dt`b02?`4h4-gU)6cZL07aAQL92^=RAtNIrASEdyDJ>`{C?+g0 zEi^eZGcz$bJv%!)Hawm}cx7c}YHMp?Zg^vIeQ#6Gsrn*EMaBo2CRmlG0)|j+leka+`#N0Ch_e963BpMBrQ? zkx$fD#m+vO2T=0z_CN2;?%8+era}hhq`h5R`@6Ys_nSSo_u1q5KNM_Fe>je~QZf=s z2ql7Fl;U{NFG|q(`NJQE0OQmsn6SM^DNb;IVbGrpMvf3FK33`@!88pU9%3vgd?e{J zELbSd-IWrX9oJXfb4A0YXmHot-7X`P=HJsg?Z4%_famo}Gtxq3J?dg|Yld(v%l@x0z1aksE+sLup#-`7I zSfbmcC@ZQqyc&Anu#Q zt?w_S5*)$uKZ`d9Z?G-GF}C-ia(vW+(wY99eSPgxGV$JmWe#&wD1`}M2m~wPv+>+W zB0tLHx!@XXVLK0PY)kM?>sjh%FQE#5KVH)o+(;x*X1>GvgE<;~6-_rMnolbezKDP&c1Mmx35N_)LTz+qRXQvjNPqS4cN2Bm9fur07m}w4h z`$eb>e;5lk_3Qgaio35YdFmB`@y)NYm7vJy5F8#U+`PZD)z|mCSaqv^!jZAyTkO?N z+C^yT$-jx4*tbPUUA0o62n3EOyk>At&F1U;HW>rUd1?=S#&<7)17y9u - - libprs500 - manual - - libprs500 - - - - libprs500 - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - - - cli-isbndb.html - cli-pdfreflow.html - cli-mobi2lrf.html - cli-lrf-meta.html - cli-lit2lrf.html - faq.html - cli-lrf2lrs.html - cli-index.html - cli-web2lrf.html - cli-lrs2lrf.html - cli-txt2lrf.html - start.html - cli-web2disk.html - gui.html - cli-opf-meta.html - cli-html2lrf.html - cli-rtf2lrf.html - cli-librarything.html - cli-epub2lrf.html - cli-rtf-meta.html - cli-pdf2lrf.html - cli-lrf2html.html - cli-any2lrf.html - cli-mobi2oeb.html - styles/common.css - images/edit_meta_information.png - images/remove_books.png - images/book_details.png - images/search_sort.png - images/search_button.png - images/convert_ebooks.png - images/add_books.png - images/save_to_disk.png - images/actions.png - images/catalogs.png - images/valid.png - images/jobs.png - images/send_to_device.png - images/configuration.png - images/search.png - images/news.png - images/view.png - images/fetch_news.png - images/cli.png - - - - \ No newline at end of file diff --git a/src/libprs500/manual/libprs500.webprj b/src/libprs500/manual/libprs500.webprj deleted file mode 100644 index 726cfad3c4..0000000000 --- a/src/libprs500/manual/libprs500.webprj +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - -//W3C//DTD XHTML 1.1//EN - - - - - - - templates/ - toolbars/ - - - - - - - - - - - - - - - - - - - - diff --git a/src/libprs500/manual/make.py b/src/libprs500/manual/make.py index 427604c8ea..b112e4ce31 100644 --- a/src/libprs500/manual/make.py +++ b/src/libprs500/manual/make.py @@ -17,13 +17,29 @@ import sys, glob, mechanize, time, subprocess, os, shutil, re from tempfile import NamedTemporaryFile -from xml.etree.ElementTree import parse, tostring, fromstring +from genshi.template import TemplateLoader, MarkupTemplate + + +if not os.path.exists('build'): + os.mkdir('build') # Load libprs500 from source copy sys.path.insert(1, os.path.dirname(os.path.dirname(os.getcwdu()))) from libprs500.ebooks.BeautifulSoup import BeautifulSoup from libprs500.linux import entry_points +from libprs500 import __appname__, __author__, __version__ + +class Template(MarkupTemplate): + + def generate(self, *args, **kwargs): + kwdargs = dict(app=__appname__, author=__author__.partition('<')[0].strip(), + version=__version__, footer=True) + kwdargs.update(kwargs) + return MarkupTemplate.generate(self, *args, **kwdargs) + +loader = TemplateLoader(os.path.abspath('templates'), auto_reload=True, + variable_lookup='strict', default_class=Template) def browser(): opener = mechanize.Browser() @@ -32,31 +48,11 @@ def browser(): opener.addheaders = [('User-agent', 'Mozilla/5.0 (X11; U; i686 Linux; en_US; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.4')] return opener -def update_manifest(src): - root = fromstring(src) - files = root.find('filterSection').find('files') - attrs = files.attrib.copy() - files.clear() - files.attrib = attrs - files.text = '\n%12s'%' ' - files.tail = '\n%4s'%' ' - - for f in glob.glob('*.html')+glob.glob('styles/*.css')+glob.glob('images/*'): - if f.startswith('preview') or f in ('navtree.html', 'index.html'): - continue - el = fromstring('%s'%f) - el.tail = '\n%12s'%' ' - files.append(el) - el.tail = '\n%8s'%' ' - - return tostring(root, 'UTF-8').decode('UTF-8') - - def validate(file=None): br = browser() - files = [file] if file is not None else glob.glob('*.html') + files = [file] if file is not None else glob.glob('build/*.html') for f in files: - if f.startswith('preview-'): + if f.endswith('navtree.html'): continue print 'Validating', f raw = open(f).read() @@ -74,14 +70,7 @@ def validate(file=None): return def clean(): - for pat in ('preview-*.html', '*.qhc', '*.qch', 'cli-*.html', '~/.assistant/libprs500*'): - for f in glob.glob(pat): - f = os.path.abspath(os.path.expanduser(f)) - if os.path.exists(f): - if os.path.isdir(f): - shutil.rmtree(f) - else: - os.unlink(f) + shutil.rmtree('build') return 0 def compile_help(): @@ -91,92 +80,53 @@ def compile_help(): QCG = os.path.join(QTBIN, 'qcollectiongenerator') QTA = os.path.join(QTBIN, 'assistant') os.environ['LD_LIBRARY_PATH'] = QTLIB - for f in ('libprs500.qch', 'libprs500.qhc'): + for f in ('build/%s.qch'%__appname__, 'build/%s.qhc'%__appname__): if os.path.exists(f): os.unlink(f) - subprocess.check_call((QCG, 'libprs500.qhcp')) - subprocess.call((QTA, '-collectionFile', 'libprs500.qhc')) + cwd = os.getcwd() + os.chdir('build') + try: + subprocess.check_call((QCG, __appname__+'.qhcp', '-o', __appname__+'.qhc')) + subprocess.call((QTA, '-collectionFile', __appname__+'.qhc')) + finally: + os.chdir(cwd) -def populate_section(secref, items, src): - root = fromstring(src) - toc = root.find('filterSection').find('toc') - sec = None - if secref is None: - sec = toc - ss = '\n%8s'%' ' - ls = '\n%12s'%' ' - else: - for c in toc.findall('section'): - if c.attrib['ref'] == secref: - sec = c - break - ss = '\n%12s'%' ' - ls = '\n%16s'%' ' - - attr = sec.attrib.copy() - tail = sec.tail - sec.clear() - sec.attrib = attr - sec.tail = tail - sec.text = ls - secs = ['
\n'%i for i in items] - sec.tail = ss - for i in secs: - el = fromstring(i) - sec.append(el) - el.tail = ss if i is secs[-1] else ls - - raw = tostring(root, 'UTF-8') - - return raw.decode('UTF-8') - -def populate_faq(src): - soup = BeautifulSoup(open('faq.html').read().decode('UTF-8')) - items = [] - toc = soup.find('div', id="toc") - for a in toc('a', href=True): - items.append(('faq.html%s'%a['href'], a.string)) - - return populate_section('faq.html', items, src=src) - -def populate_cli(src): - cmds = [] - for f in glob.glob('cli-*.html'): - cmds.append(f[4:].rpartition('.')[0]) - - items = [('cli-%s.html'%i, i) for i in cmds] - return populate_section('cli-index.html', items, src) - -def populate_toc(src): - soup = BeautifulSoup(open('start.html', 'rb').read().decode('UTF-8')) - sections = [('start.html', 'Start')] - for a in soup.find(id='toc').findAll('a'): - sections.append((a['href'], a.string)) - - return populate_section(None, sections, src) - -def populate_gui(src): - soup = BeautifulSoup(open('gui.html', 'rb').read().decode('UTF-8')) - sections = [] - for a in soup.find(id='toc').findAll('a'): - sections.append(('gui.html'+a['href'], a.string)) - - return populate_section('gui.html', sections, src) +def get_subsections(section, level=0, max_level=1, prefix='templates'): + src = os.path.join(prefix, section) + if not os.path.exists(src): + return [] + soup = BeautifulSoup(open(src, 'rb').read().decode('UTF-8')) + toc = soup.find(id='toc') + if toc is None: + return [] + return [dict(href=section+a['href'] if a['href'].startswith('#') else a['href'], + title=a.string.replace('&', '&'), + subsections=get_subsections(a['href'], level=1, + prefix=prefix, max_level=max_level) if level', '>') - for cmd, parser in documented_cmds: - output = open('cli-%s.html'%cmd, 'wb') - template = open('templates/basic.html', 'rb').read().decode('utf-8') - template = re.sub('\s*', '%s'%cmd, template) - usage = [sanitize_text(i) for i in parser.usage.replace('%prog', cmd).splitlines(True) if i] - usage[0] = '
%s
'%usage[0] - usage[1:] = [i.replace(cmd, '%s'%cmd) for i in usage[1:]] - usage = ''.join(usage).replace('\n', '
') - body = ('\n

%s

\n'%cmd)+'
\n%s\n
'%usage - - - groups = {} - for grp in parser.option_groups: - groups[(grp.title, grp.description)] = grp.option_list - - def group_html(title, description, option_list): - res = [] - - if title is not None: - res.append('

%s

'%title) - if description is not None: - res.append('%s
 '%sanitize_text(description)) - for opt in option_list: - shf = ' '.join(opt._short_opts) - lgf = opt.get_opt_string() - name = '%s
%s'%(lgf, shf) - help = sanitize_text(opt.help) if opt.help else '' - res.append('%s%s'%(name, help)) - return '\n%8s'%' ' + ('\n%8s'%' ').join(res) - - - gh = [group_html(None, None, parser.option_list)] - for title, desc in groups.keys(): - olist = groups[(title, desc)] - gh.append(group_html(title, desc, olist)) - - if ''.join(gh).strip(): - body += '\n

[options]

\n' - body += '\n \n%s\n
\n'%'\n'.join(gh) - output.write(template.replace('%body', body)) - - uc_html = '\n
    \n%s
\n'%'\n'.join(\ - '
  • %s
  • \n'%i for i in undocumented_cmds) - dc_html = '\n
      \n%s
    \n'%'\n'.join(\ - '
  • %s
  • \n'%(i[0], i[0]) for i in documented_cmds) + template = loader.load('cli-cmd.html') + open('build/cli-%s.html'%cmd, 'wb').write( + template.generate(cmd=cmd, parser=parser).render(doctype='xhtml')) - body = '

    The Command Line Interface

    \n' - body += '
    CLI
    ' - body += '

    %s

    \n'%'libprs500 has a very comprehensive command line interface to perform most operations that can be performed by the GUI.' - body += '

    Documented commands

    \n'+dc_html - body += '

    Undocumented commands

    \n'+uc_html - body += '

    You can see usage for undocumented commands by executing them without arguments in a terminal

    ' + documented = [i[0] for i in documented_cmds] + template = loader.load('cli-index.html') - template = open('templates/basic.html', 'rb').read().decode('utf-8') - template = re.sub('\s*', '%s'%'Command Line Interface', template) - open('cli-index.html', 'wb').write(template.replace('%body', body)) + open('build/cli-index.html', 'wb').write( + template.generate(documented=documented, undocumented=undocumented_cmds).render(doctype='xhtml')) -def html(src='libprs500.qhp'): - root = parse(src).getroot() - toc = root.find('filterSection').find('toc') - - def is_leaf(sec): - return not sec.findall('section') - - - def process_branch(branch, toplevel=False): - parent = [] - for sec in branch.findall('section'): - title = re.sub('&(?!amp;)', '&', sec.attrib['title']) - html = '
  • \n%s\n
  • \n'%(sec.attrib['ref'], title) - lc = 'toplevel' if toplevel else 'nottoplevel' - html=html.replace('||||', '%s ||||'%lc) +def html(): + toc = get_subsections('start.html', prefix='build') + toc.insert(0, dict(title='Start', href='start.html', subsections=[])) + template = loader.load('navtree.html') + dt = ('html', "-//W3C//DTD HTML 4.01 Transitional//EN", + "http://www.w3.org/TR/html4/loose.dtd") + raw = template.generate(footer=False, toc=toc).render(doctype=dt) + raw = re.sub(r']+>', '', raw) + open('build'+os.sep+'navtree.html', 'wb').write(raw) - type = 'file' - if not is_leaf(sec): - html = html.replace('','%s\n'%process_branch(sec)) - type = 'folder' - - parent.append(html.replace('||||', type)) - html = '\n'.join(parent) - if toplevel: - return html - return '
      \n%s\n
    '%html - - tree = process_branch(toc, True) + +def render(): + for d in ('images', 'styles'): + tgt = os.path.join('build', d) + if not os.path.exists(tgt): + os.mkdir(tgt) + for f in glob.glob(d+os.sep+'*'): + if os.path.isfile(f): + ftgt = os.path.join(tgt, os.path.basename(f)) + if os.path.exists(ftgt): + os.unlink(ftgt) + os.link(f, ftgt) - template = open('templates/navtree.html').read() - open('navtree.html', 'wb').write(template.replace('%tree', tree)+'\n') + sections = [i['href'] for i in get_subsections('start.html')] + sections.remove('cli-index.html') + + for f in sections + ['index.html', 'start.html']: + kwdargs = {} + if not isinstance(f, basestring): + f, kwdargs = f + dt = f.rpartition('.')[-1] + if dt == 'html': + dt = 'xhtml' + if f == 'index.html': + dt=('html', '-//W3C//DTD XHTML 1.0 Frameset//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd') + raw = loader.load(f).generate(**kwdargs).render(doctype=dt) + open(os.path.join('build', f), 'wb').write(raw) + def all(opts): clean() - cli_docs() - qhp() html() if opts.validate: validate() diff --git a/src/libprs500/manual/templates/about.txt b/src/libprs500/manual/templates/about.txt new file mode 100644 index 0000000000..3a83a1c360 --- /dev/null +++ b/src/libprs500/manual/templates/about.txt @@ -0,0 +1 @@ +${app} is an ebook management application with support for various ebook readers. Created by ${author} © 2007. diff --git a/src/libprs500/manual/libprs500.qhcp b/src/libprs500/manual/templates/app.qhcp similarity index 54% rename from src/libprs500/manual/libprs500.qhcp rename to src/libprs500/manual/templates/app.qhcp index 4d99522707..4d5af9d701 100644 --- a/src/libprs500/manual/libprs500.qhcp +++ b/src/libprs500/manual/templates/app.qhcp @@ -1,29 +1,29 @@ - + - libprs500 Help - qthelp://libprs500/manual/start.html - ../gui2/images/library.png + ${app} User Manual + qthelp://${app}/manual/start.html + ../../gui2/images/library.png false false true - About libprs500 + About ${app} about.txt - ../gui2/images/dialog_information.svg + ../../gui2/images/dialog_information.svg - libprs500.qhp - libprs500.qch + ${app}.qhp + ${app}.qch - libprs500.qch + ${app}.qch diff --git a/src/libprs500/manual/templates/app.qhp b/src/libprs500/manual/templates/app.qhp new file mode 100644 index 0000000000..c4d91919ca --- /dev/null +++ b/src/libprs500/manual/templates/app.qhp @@ -0,0 +1,30 @@ + + + ${app} + manual + + + + + +
    + +
    + + +
    + +
    + + + + + ${file} + + + + + + \ No newline at end of file diff --git a/src/libprs500/manual/templates/cli-cmd.html b/src/libprs500/manual/templates/cli-cmd.html new file mode 100644 index 0000000000..1604a04bed --- /dev/null +++ b/src/libprs500/manual/templates/cli-cmd.html @@ -0,0 +1,47 @@ +%s'%cmd) for i in usage] + groups = [(None, None, parser.option_list)] + for grp in parser.option_groups: + groups.append((grp.title, grp.description, grp.option_list)) +?> + + + + + + ${cmd} + + + +
    ${cmdline}
    +

    + ${HTML(line)}
    +

    +

    [options]

    + + + + + + + + + +

    ${title}

    ${desc}
     
    + ${option.get_opt_string()}
    ${short} +
    ${help}
    + + + + \ No newline at end of file diff --git a/src/libprs500/manual/templates/cli-index.html b/src/libprs500/manual/templates/cli-index.html new file mode 100644 index 0000000000..d50d94c867 --- /dev/null +++ b/src/libprs500/manual/templates/cli-index.html @@ -0,0 +1,38 @@ + + + + + + + ${title} + + + +
    CLI
    +

    + ${app} has a very comprehensive command line + interface to perform most operations that can be performed by the GUI. +

    +

    Documented commands

    + +

    Undocumented commands

    +
      +
    • ${item}
    • +
    +

    You can see usage for undocumented commands by executing them without arguments in a terminal

    + + + + \ No newline at end of file diff --git a/src/libprs500/manual/faq.html b/src/libprs500/manual/templates/faq.html similarity index 52% rename from src/libprs500/manual/faq.html rename to src/libprs500/manual/templates/faq.html index 04d4b07597..d5788f221f 100644 --- a/src/libprs500/manual/faq.html +++ b/src/libprs500/manual/templates/faq.html @@ -1,14 +1,18 @@ - - - - + + + + + - - - - Frequently Asked Questions - + ${title}