2 # -*- coding: utf-8 -*-
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
9 # Full author contact details are available in file CREDITS.
11 import sys, os, re, shutil, glob, logging
14 logging.basicConfig(level = logging.DEBUG,
15 format = '%(levelname)s: %(message)s', # ignore application name
16 filename = 'configure.log',
19 # Add a handler to log to console
20 console = logging.StreamHandler()
21 console.setLevel(logging.INFO) # the console only print out general information
22 formatter = logging.Formatter('%(message)s') # only print out the message itself
23 console.setFormatter(formatter)
24 logger = logging.getLogger('LyX')
25 logger.addHandler(console)
27 def writeToFile(filename, lines, append = False):
28 " utility function: write or append lines to filename "
30 file = open(filename, 'a')
32 file = open(filename, 'w')
38 ''' utility function: shortcut for appending lines to outfile
39 add newline at the end of lines.
41 if lines.strip() != '':
42 writeToFile(outfile, lines + '\n', append = True)
43 logger.debug('Add to RC:\n' + lines + '\n\n')
46 def removeFiles(filenames):
47 '''utility function: 'rm -f'
48 ignore errors when file does not exist, or is a directory.
50 for file in filenames:
53 logger.debug('Removing file %s' % file)
55 logger.debug('Failed to remove file %s' % file)
60 '''utility function: run a command and get its output as a string
70 ''' I do not really know why this is useful, but we might as well keep it.
72 Only set these to C if already set. These must not be set unconditionally
73 because not all systems understand e.g. LANG=C (notably SCO).
74 Fixing LC_MESSAGES prevents Solaris sh from translating var values in set!
75 Non-C LC_CTYPE values break the ctype check.
77 os.environ['LANG'] = os.getenv('LANG', 'C')
78 os.environ['LC'] = os.getenv('LC_ALL', 'C')
79 os.environ['LC_MESSAGE'] = os.getenv('LC_MESSAGE', 'C')
80 os.environ['LC_CTYPE'] = os.getenv('LC_CTYPE', 'C')
83 def createDirectories():
84 ''' Create the build directories if necessary '''
85 for dir in ['bind', 'clipart', 'doc', 'examples', 'images', 'kbd', \
86 'layouts', 'scripts', 'templates', 'ui' ]:
87 if not os.path.isdir( dir ):
90 logger.debug('Create directory %s.' % dir)
92 logger.error('Failed to create directory %s.' % dir)
97 ''' Determine the path-style needed by the TeX engine on Win32 (Cygwin) '''
98 windows_style_tex_paths = ''
100 return windows_style_tex_paths
101 if os.name == 'nt' or sys.platform == 'cygwin':
102 from tempfile import mkstemp
103 fd, tmpfname = mkstemp(suffix='.ltx')
105 from ctypes import windll, create_unicode_buffer
106 GetShortPathName = windll.kernel32.GetShortPathNameW
107 longname = unicode(tmpfname)
108 shortname = create_unicode_buffer(len(longname)+1)
109 if GetShortPathName(longname, shortname, len(longname)+1):
110 inpname = shortname.value.replace('\\', '/')
112 inpname = tmpfname.replace('\\', '/')
114 inpname = cmdOutput('cygpath -m ' + tmpfname)
115 logname = os.path.basename(inpname.replace('.ltx', '.log'))
116 inpname = inpname.replace('~', '\\string~')
117 os.write(fd, r'\relax')
119 latex_out = cmdOutput(r'latex "\nonstopmode\input{%s}"' % inpname)
120 if 'Error' in latex_out:
121 latex_out = cmdOutput(r'latex "\nonstopmode\input{\"%s\"}"' % inpname)
122 if 'Error' in latex_out:
123 logger.warning("configure: TeX engine needs posix-style paths in latex files")
124 windows_style_tex_paths = 'false'
126 logger.info("configure: TeX engine needs windows-style paths in latex files")
127 windows_style_tex_paths = 'true'
128 removeFiles([tmpfname, logname, 'texput.log'])
129 return windows_style_tex_paths
132 ## Searching some useful programs
133 def checkProg(description, progs, rc_entry = [], path = [], not_found = ''):
135 This function will search a program in $PATH plus given path
136 If found, return directory and program name (not the options).
138 description: description of the program
140 progs: check programs, for each prog, the first word is used
141 for searching but the whole string is used to replace
142 %% for a rc_entry. So, feel free to add '$$i' etc for programs.
144 path: additional pathes
146 rc_entry: entry to outfile, can be
147 1. emtpy: no rc entry will be added
148 2. one pattern: %% will be replaced by the first found program,
149 or '' if no program is found.
150 3. several patterns for each prog and not_found. This is used
151 when different programs have different usages. If you do not
152 want not_found entry to be added to the RC file, you can specify
153 an entry for each prog and use '' for the not_found entry.
155 not_found: the value that should be used instead of '' if no program
159 # one rc entry for each progs plus not_found entry
160 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
161 logger.error("rc entry should have one item or item for each prog and not_found.")
163 logger.info('checking for ' + description + '...')
164 ## print '(' + ','.join(progs) + ')',
165 for idx in range(len(progs)):
166 # ac_prog may have options, ac_word is the command name
168 ac_word = ac_prog.split(' ')[0]
169 msg = '+checking for "' + ac_word + '"... '
170 path = os.environ["PATH"].split(os.pathsep) + path
172 if "PATHEXT" in os.environ:
173 extlist = extlist + os.environ["PATHEXT"].split(os.pathsep)
176 if os.path.isfile( os.path.join(ac_dir, ac_word + ext) ):
177 logger.info(msg + ' yes')
178 # write rc entries for this command
179 if len(rc_entry) == 1:
180 addToRC(rc_entry[0].replace('%%', ac_prog))
181 elif len(rc_entry) > 1:
182 addToRC(rc_entry[idx].replace('%%', ac_prog))
183 return [ac_dir, ac_word]
185 logger.info(msg + ' no')
186 # write rc entries for 'not found'
187 if len(rc_entry) > 0: # the last one.
188 addToRC(rc_entry[-1].replace('%%', not_found))
189 return ['', not_found]
192 def checkProgAlternatives(description, progs, rc_entry = [], alt_rc_entry = [], path = [], not_found = ''):
194 The same as checkProg, but additionally, all found programs will be added
197 # one rc entry for each progs plus not_found entry
198 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
199 logger.error("rc entry should have one item or item for each prog and not_found.")
201 logger.info('checking for ' + description + '...')
202 ## print '(' + ','.join(progs) + ')',
205 real_ac_word = not_found
206 for idx in range(len(progs)):
207 # ac_prog may have options, ac_word is the command name
209 ac_word = ac_prog.split(' ')[0]
210 msg = '+checking for "' + ac_word + '"... '
211 path = os.environ["PATH"].split(os.pathsep) + path
213 if "PATHEXT" in os.environ:
214 extlist = extlist + os.environ["PATHEXT"].split(os.pathsep)
218 if os.path.isfile( os.path.join(ac_dir, ac_word + ext) ):
219 logger.info(msg + ' yes')
220 pr = re.compile(r'(\\\S+)(.*)$')
222 # write rc entries for this command
223 if found_prime == False:
224 if len(rc_entry) == 1:
225 addToRC(rc_entry[0].replace('%%', ac_prog))
226 elif len(rc_entry) > 1:
227 addToRC(rc_entry[idx].replace('%%', ac_prog))
229 real_ac_word = ac_word
231 if len(alt_rc_entry) == 1:
232 alt_rc = alt_rc_entry[0]
234 # if no explicit alt_rc is given, construct one
235 m = pr.match(rc_entry[0])
237 alt_rc = m.group(1) + "_alternatives" + m.group(2)
238 addToRC(alt_rc.replace('%%', ac_prog))
239 elif len(alt_rc_entry) > 1:
240 alt_rc = alt_rc_entry[idx]
242 # if no explicit alt_rc is given, construct one
243 m = pr.match(rc_entry[idx])
245 alt_rc = m.group(1) + "_alternatives" + m.group(2)
246 addToRC(alt_rc.replace('%%', ac_prog))
251 if found_alt == False:
253 logger.info(msg + ' no')
255 return [real_ac_dir, real_ac_word]
256 # write rc entries for 'not found'
257 if len(rc_entry) > 0: # the last one.
258 addToRC(rc_entry[-1].replace('%%', not_found))
259 return ['', not_found]
262 def addViewerAlternatives(rcs):
263 r = re.compile(r'\\Format (\S+).*$')
266 for idxx in range(len(rcs)):
270 alt = r'\viewer_alternatives ' + m.group(1) + " %%"
272 m = r.match(rcs[idxx])
276 alt += r'\viewer_alternatives ' + m.group(1) + " %%"
280 def addEditorAlternatives(rcs):
281 r = re.compile(r'\\Format (\S+).*$')
284 for idxx in range(len(rcs)):
288 alt = r'\editor_alternatives ' + m.group(1) + " %%"
290 m = r.match(rcs[idxx])
294 alt += r'\editor_alternatives ' + m.group(1) + " %%"
298 def checkViewer(description, progs, rc_entry = [], path = []):
299 ''' The same as checkProgAlternatives, but for viewers '''
300 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
301 logger.error("rc entry should have one item or item for each prog and not_found.")
304 for idx in range(len(progs)):
305 if len(rc_entry) == 1:
306 rcs = rc_entry[0].split('\n')
307 alt = addViewerAlternatives(rcs)
308 alt_rc_entry.insert(0, alt)
309 elif len(rc_entry) > 1:
310 rcs = rc_entry[idx].split('\n')
311 alt = addViewerAlternatives(rcs)
312 alt_rc_entry.insert(idx, alt)
313 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
316 def checkEditor(description, progs, rc_entry = [], path = []):
317 ''' The same as checkProgAlternatives, but for editors '''
318 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
319 logger.error("rc entry should have one item or item for each prog and not_found.")
322 for idx in range(len(progs)):
323 if len(rc_entry) == 1:
324 rcs = rc_entry[0].split('\n')
325 alt = addEditorAlternatives(rcs)
326 alt_rc_entry.insert(0, alt)
327 elif len(rc_entry) > 1:
328 rcs = rc_entry[idx].split('\n')
329 alt = addEditorAlternatives(rcs)
330 alt_rc_entry.insert(idx, alt)
331 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
334 def checkViewerNoRC(description, progs, rc_entry = [], path = []):
335 ''' The same as checkViewer, but do not add rc entry '''
336 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
337 logger.error("rc entry should have one item or item for each prog and not_found.")
340 for idx in range(len(progs)):
341 if len(rc_entry) == 1:
342 rcs = rc_entry[0].split('\n')
343 alt = addViewerAlternatives(rcs)
344 alt_rc_entry.insert(0, alt)
345 elif len(rc_entry) > 1:
346 rcs = rc_entry[idx].split('\n')
347 alt = addViewerAlternatives(rcs)
348 alt_rc_entry.insert(idx, alt)
350 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
353 def checkEditorNoRC(description, progs, rc_entry = [], path = []):
354 ''' The same as checkViewer, but do not add rc entry '''
355 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
356 logger.error("rc entry should have one item or item for each prog and not_found.")
359 for idx in range(len(progs)):
360 if len(rc_entry) == 1:
361 rcs = rc_entry[0].split('\n')
362 alt = addEditorAlternatives(rcs)
363 alt_rc_entry.insert(0, alt)
364 elif len(rc_entry) > 1:
365 rcs = rc_entry[idx].split('\n')
366 alt = addEditorAlternatives(rcs)
367 alt_rc_entry.insert(idx, alt)
369 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
372 def checkViewerEditor(description, progs, rc_entry = [], path = []):
373 ''' The same as checkProgAlternatives, but for viewers and editors '''
374 checkEditorNoRC(description, progs, rc_entry, path)
375 return checkViewer(description, progs, rc_entry, path)
379 ''' Check whether DTL tools are available (Windows only) '''
380 # Find programs! Returned path is not used now
381 if ((os.name == 'nt' or sys.platform == 'cygwin') and
382 checkProg('DVI to DTL converter', ['dv2dt']) != ['', ''] and
383 checkProg('DTL to DVI converter', ['dt2dv']) != ['', '']):
390 def checkLatex(dtl_tools):
391 ''' Check latex, return lyx_check_config '''
392 path, LATEX = checkProg('a Latex2e program', ['latex $$i', 'latex2e $$i'])
393 path, PPLATEX = checkProg('a DVI postprocessing program', ['pplatex $$i'])
394 #-----------------------------------------------------------------
395 path, PLATEX = checkProg('pLaTeX, the Japanese LaTeX', ['platex $$i'])
397 # check if PLATEX is pLaTeX2e
398 writeToFile('chklatex.ltx', '''
402 # run platex on chklatex.ltx and check result
403 if cmdOutput(PLATEX + ' chklatex.ltx').find('pLaTeX2e') != -1:
404 # We have the Japanese pLaTeX2e
405 addToRC(r'\converter platex dvi "%s" "latex=platex"' % PLATEX)
408 removeFiles(['chklatex.ltx', 'chklatex.log'])
409 #-----------------------------------------------------------------
410 # use LATEX to convert from latex to dvi if PPLATEX is not available
414 # Windows only: DraftDVI
415 addToRC(r'''\converter latex dvi2 "%s" "latex"
416 \converter dvi2 dvi "python -tt $$s/scripts/clean_dvi.py $$i $$o" ""''' % PPLATEX)
418 addToRC(r'\converter latex dvi "%s" "latex"' % PPLATEX)
421 # Check if latex is usable
422 writeToFile('chklatex.ltx', '''
423 \\nonstopmode\\makeatletter
424 \\ifx\\undefined\\documentclass\\else
425 \\message{ThisIsLaTeX2e}
429 # run latex on chklatex.ltx and check result
430 if cmdOutput(LATEX + ' chklatex.ltx').find('ThisIsLaTeX2e') != -1:
434 logger.warning("Latex not usable (not LaTeX2e) ")
435 # remove temporary files
436 removeFiles(['chklatex.ltx', 'chklatex.log'])
441 ''' Check if luatex is there and usable '''
442 path, LUATEX = checkProg('LuaTeX', ['lualatex $$i'])
443 path, DVILUATEX = checkProg('LuaTeX (DVI)', ['dvilualatex $$i'])
445 # luatex binary is there
446 msg = "checking if LuaTeX is usable ..."
447 # Check if luatex is usable
448 writeToFile('luatest.tex', '''
449 \\nonstopmode\\documentclass{minimal}
450 \\usepackage{fontspec}
455 # run lualatex on luatest.tex and check result
456 luatest = cmdOutput(LUATEX + ' luatest.tex')
457 if luatest.find('XeTeX is required to compile this document') != -1:
458 # fontspec/luatex too old! We do not support this version.
459 logger.info(msg + ' no (probably not recent enough)')
460 elif luatest.find('! LaTeX Error: File `fontspec.sty\' not found') != -1:
462 logger.info(msg + ' no (missing fontspec)')
465 logger.info(msg + ' yes')
466 addToRC(r'\converter luatex pdf5 "%s" "latex=lualatex"' % LUATEX)
468 addToRC(r'\converter luatex dvi3 "%s" "latex=lualatex"' % DVILUATEX)
469 # remove temporary files
470 removeFiles(['luatest.tex', 'luatest.log', 'luatest.aux', 'luatest.pdf'])
473 def checkModule(module):
474 ''' Check for a Python module, return the status '''
475 msg = 'checking for "' + module + ' module"... '
478 logger.info(msg + ' yes')
481 logger.info(msg + ' no')
485 def checkFormatEntries(dtl_tools):
486 ''' Check all formats (\Format entries) '''
487 checkViewerEditor('a Tgif viewer and editor', ['tgif'],
488 rc_entry = [r'\Format tgif obj Tgif "" "%%" "%%" "vector"'])
490 checkViewerEditor('a FIG viewer and editor', ['xfig', 'jfig3-itext.jar', 'jfig3.jar'],
491 rc_entry = [r'\Format fig fig FIG "" "%%" "%%" "vector"'])
493 checkViewerEditor('a Dia viewer and editor', ['dia'],
494 rc_entry = [r'\Format dia dia DIA "" "%%" "%%" "vector"'])
496 checkViewerEditor('a Grace viewer and editor', ['xmgrace'],
497 rc_entry = [r'\Format agr agr Grace "" "%%" "%%" "vector"'])
499 checkViewerEditor('a FEN viewer and editor', ['xboard -lpf $$i -mode EditPosition'],
500 rc_entry = [r'\Format fen fen FEN "" "%%" "%%" ""'])
502 checkViewerEditor('a SVG viewer and editor', ['inkscape'],
503 rc_entry = [r'\Format svg svg SVG "" "%%" "%%" "vector"'])
505 path, iv = checkViewerNoRC('a raster image viewer', ['xv', 'kview', 'gimp-remote', 'gimp'],
506 rc_entry = [r'''\Format bmp bmp BMP "" "%s" "%s" ""
507 \Format gif gif GIF "" "%s" "%s" ""
508 \Format jpg jpg JPEG "" "%s" "%s" ""
509 \Format pbm pbm PBM "" "%s" "%s" ""
510 \Format pgm pgm PGM "" "%s" "%s" ""
511 \Format png png PNG "" "%s" "%s" ""
512 \Format ppm ppm PPM "" "%s" "%s" ""
513 \Format tiff tif TIFF "" "%s" "%s" ""
514 \Format xbm xbm XBM "" "%s" "%s" ""
515 \Format xpm xpm XPM "" "%s" "%s" ""'''])
516 path, ie = checkEditorNoRC('a raster image editor', ['gimp-remote', 'gimp'],
517 rc_entry = [r'''\Format bmp bmp BMP "" "%s" "%s" ""
518 \Format gif gif GIF "" "%s" "%s" ""
519 \Format jpg jpg JPEG "" "%s" "%s" ""
520 \Format pbm pbm PBM "" "%s" "%s" ""
521 \Format pgm pgm PGM "" "%s" "%s" ""
522 \Format png png PNG "" "%s" "%s" ""
523 \Format ppm ppm PPM "" "%s" "%s" ""
524 \Format tiff tif TIFF "" "%s" "%s" ""
525 \Format xbm xbm XBM "" "%s" "%s" ""
526 \Format xpm xpm XPM "" "%s" "%s" ""'''])
527 addToRC(r'''\Format bmp bmp BMP "" "%s" "%s" ""
528 \Format gif gif GIF "" "%s" "%s" ""
529 \Format jpg jpg JPEG "" "%s" "%s" ""
530 \Format pbm pbm PBM "" "%s" "%s" ""
531 \Format pgm pgm PGM "" "%s" "%s" ""
532 \Format png png PNG "" "%s" "%s" ""
533 \Format ppm ppm PPM "" "%s" "%s" ""
534 \Format tiff tif TIFF "" "%s" "%s" ""
535 \Format xbm xbm XBM "" "%s" "%s" ""
536 \Format xpm xpm XPM "" "%s" "%s" ""''' % \
537 (iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie) )
539 checkViewerEditor('a text editor', ['xemacs', 'gvim', 'kedit', 'kwrite', 'kate', \
540 'nedit', 'gedit', 'notepad'],
541 rc_entry = [r'''\Format asciichess asc "Plain text (chess output)" "" "" "%%" ""
542 \Format asciiimage asc "Plain text (image)" "" "" "%%" ""
543 \Format asciixfig asc "Plain text (Xfig output)" "" "" "%%" ""
544 \Format dateout tmp "date (output)" "" "" "%%" ""
545 \Format docbook sgml DocBook B "" "%%" "document,menu=export"
546 \Format docbook-xml xml "Docbook (XML)" "" "" "%%" "document,menu=export"
547 \Format dot dot "Graphviz Dot" "" "" "%%" "vector"
548 \Format platex tex "LaTeX (pLaTeX)" "" "" "%%" "document,menu=export"
549 \Format literate nw NoWeb N "" "%%" "document,menu=export"
550 \Format sweave Rnw "Sweave" S "" "%%" "document,menu=export"
551 \Format lilypond ly "LilyPond music" "" "" "%%" "vector"
552 \Format lilypond-book lytex "LilyPond book (LaTeX)" "" "" "%%" "document,menu=export"
553 \Format latex tex "LaTeX (plain)" L "" "%%" "document,menu=export"
554 \Format luatex tex "LaTeX (LuaTeX)" "" "" "%%" "document,menu=export"
555 \Format pdflatex tex "LaTeX (pdflatex)" "" "" "%%" "document,menu=export"
556 \Format xetex tex "LaTeX (XeTeX)" "" "" "%%" "document,menu=export"
557 \Format text txt "Plain text" a "" "%%" "document,menu=export"
558 \Format text2 txt "Plain text (pstotext)" "" "" "%%" "document"
559 \Format text3 txt "Plain text (ps2ascii)" "" "" "%%" "document"
560 \Format text4 txt "Plain text (catdvi)" "" "" "%%" "document"
561 \Format textparagraph txt "Plain Text, Join Lines" "" "" "%%" "document"''' ])
562 #Spreadsheets using ssconvert from gnumeric
563 checkViewer('gnumeric spreadsheet software', ['gnumeric'],
564 rc_entry = [r'''\Format gnumeric gnumeric "Gnumeric spreadsheet" "" "" "%%" "document"
565 \Format excel xls "Excel spreadsheet" "" "" "%%" "document"
566 \Format oocalc ods "OpenOffice spreadsheet" "" "" "%%" "document"'''])
568 path, xhtmlview = checkViewer('an HTML previewer', ['firefox', 'mozilla file://$$p$$i', 'netscape'],
569 rc_entry = [r'\Format xhtml xhtml "LyXHTML" y "%%" "" "document,menu=export"'])
571 addToRC(r'\Format xhtml xhtml "LyXHTML" y "" "" "document,menu=export"')
573 checkEditor('a BibTeX editor', ['jabref', 'JabRef', \
574 'pybliographic', 'bibdesk', 'gbib', 'kbib', \
575 'kbibtex', 'sixpack', 'bibedit', 'tkbibtex' \
576 'xemacs', 'gvim', 'kedit', 'kwrite', 'kate', \
577 'nedit', 'gedit', 'notepad'],
578 rc_entry = [r'''\Format bibtex bib "BibTeX" "" "" "%%" ""''' ])
580 #checkProg('a Postscript interpreter', ['gs'],
581 # rc_entry = [ r'\ps_command "%%"' ])
582 checkViewer('a Postscript previewer', ['kghostview', 'okular', 'evince', 'gv', 'ghostview -swap'],
583 rc_entry = [r'''\Format eps eps EPS "" "%%" "" "vector"
584 \Format ps ps Postscript t "%%" "" "document,vector"'''])
585 # for xdg-open issues look here: http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg151818.html
586 checkViewer('a PDF previewer', ['kpdf', 'okular', 'evince', 'kghostview', 'xpdf', 'acrobat', 'acroread', \
588 rc_entry = [r'''\Format pdf pdf "PDF (ps2pdf)" P "%%" "" "document,vector,menu=export"
589 \Format pdf2 pdf "PDF (pdflatex)" F "%%" "" "document,vector,menu=export"
590 \Format pdf3 pdf "PDF (dvipdfm)" m "%%" "" "document,vector,menu=export"
591 \Format pdf4 pdf "PDF (XeTeX)" X "%%" "" "document,vector,menu=export"
592 \Format pdf5 pdf "PDF (LuaTeX)" u "%%" "" "document,vector,menu=export"'''])
594 checkViewer('a DVI previewer', ['xdvi', 'kdvi', 'okular', 'yap', 'dviout -Set=!m'],
595 rc_entry = [r'''\Format dvi dvi DVI D "%%" "" "document,vector,menu=export"
596 \Format dvi3 dvi "DVI (LuaTeX)" V "%%" "" "document,vector,menu=export"'''])
598 # Windows only: DraftDVI
599 addToRC(r'\Format dvi2 dvi DraftDVI "" "" "" "vector"')
601 checkViewer('an HTML previewer', ['firefox', 'mozilla file://$$p$$i', 'netscape'],
602 rc_entry = [r'\Format html html HTML H "%%" "" "document,menu=export"'])
604 checkViewerEditor('Noteedit', ['noteedit'],
605 rc_entry = [r'\Format noteedit not Noteedit "" "%%" "%%" "vector"'])
607 checkViewerEditor('an OpenDocument/OpenOffice viewer', ['swriter', 'oowriter', 'abiword'],
608 rc_entry = [r'''\Format odt odt OpenDocument "" "%%" "%%" "document,vector,menu=export"
609 \Format sxw sxw "OpenOffice.Org (sxw)" "" "" "" "document,vector"'''])
611 checkViewerEditor('a Rich Text and Word viewer', ['swriter', 'oowriter', 'abiword'],
612 rc_entry = [r'''\Format rtf rtf "Rich Text Format" "" "%%" "%%" "document,vector,menu=export"
613 \Format word doc "MS Word" W "%%" "%%" "document,vector,menu=export"'''])
615 # entries that do not need checkProg
616 addToRC(r'''\Format date "" "date command" "" "" "" ""
617 \Format csv csv "Table (CSV)" "" "" "" "document"
618 \Format fax "" Fax "" "" "" "document"
619 \Format lyx lyx LyX "" "" "" ""
620 \Format lyx13x 13.lyx "LyX 1.3.x" "" "" "" "document"
621 \Format lyx14x 14.lyx "LyX 1.4.x" "" "" "" "document"
622 \Format lyx15x 15.lyx "LyX 1.5.x" "" "" "" "document"
623 \Format lyx16x 16.lyx "LyX 1.6.x" "" "" "" "document,menu=export"
624 \Format clyx cjklyx "CJK LyX 1.4.x (big5)" "" "" "" "document"
625 \Format jlyx cjklyx "CJK LyX 1.4.x (euc-jp)" "" "" "" "document"
626 \Format klyx cjklyx "CJK LyX 1.4.x (euc-kr)" "" "" "" "document"
627 \Format lyxpreview lyxpreview "LyX Preview" "" "" "" ""
628 \Format lyxpreview-lytex lyxpreview-lytex "LyX Preview (LilyPond book)" "" "" "" ""
629 \Format lyxpreview-platex lyxpreview-platex "LyX Preview (pLaTeX)" "" "" "" ""
630 \Format pdftex pdftex_t PDFTEX "" "" "" ""
631 \Format program "" Program "" "" "" ""
632 \Format pstex pstex_t PSTEX "" "" "" ""
633 \Format wmf wmf "Windows Metafile" "" "" "" "vector"
634 \Format emf emf "Enhanced Metafile" "" "" "" "vector"
635 \Format wordhtml html "HTML (MS Word)" "" "" "" "document"
639 def checkConverterEntries():
640 ''' Check all converters (\converter entries) '''
641 checkProg('the pdflatex program', ['pdflatex $$i'],
642 rc_entry = [ r'\converter pdflatex pdf2 "%%" "latex=pdflatex"' ])
644 checkProg('XeTeX', ['xelatex $$i'],
645 rc_entry = [ r'\converter xetex pdf4 "%%" "latex=xelatex"' ])
649 ''' If we're running LyX in-place then tex2lyx will be found in
650 ../src/tex2lyx. Add this directory to the PATH temporarily and
652 Use PATH to avoid any problems with paths-with-spaces.
654 path_orig = os.environ["PATH"]
655 os.environ["PATH"] = os.path.join('..', 'src', 'tex2lyx') + \
656 os.pathsep + path_orig
658 # First search for tex2lyx with version suffix (bug 6986)
659 checkProg('a LaTeX/Noweb -> LyX converter', ['tex2lyx' + version_suffix, 'tex2lyx'],
660 rc_entry = [r'''\converter latex lyx "%% -f $$i $$o" ""
661 \converter literate lyx "%% -n -f $$i $$o" ""'''])
663 os.environ["PATH"] = path_orig
666 checkProg('a Noweb -> LaTeX converter', ['noweave -delay -index $$i > $$o'],
667 rc_entry = [r'''\converter literate latex "%%" ""
668 \converter literate pdflatex "%%" ""'''])
670 checkProg('a Sweave -> LaTeX converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxsweave.R $$p$$i $$p$$o $$e $$r'],
671 rc_entry = [r'''\converter sweave latex "%%" ""
672 \converter sweave pdflatex "%%" ""
673 \converter sweave xetex "%%" ""
674 \converter sweave luatex "%%" ""'''])
676 checkProg('an HTML -> LaTeX converter', ['html2latex $$i', 'gnuhtml2latex $$i', \
677 'htmltolatex -input $$i -output $$o', 'java -jar htmltolatex.jar -input $$i -output $$o'],
678 rc_entry = [ r'\converter html latex "%%" ""' ])
680 checkProg('an MS Word -> LaTeX converter', ['wvCleanLatex $$i $$o'],
681 rc_entry = [ r'\converter word latex "%%" ""' ])
683 # eLyXer: search as an executable (elyxer.py, elyxer)
684 path, elyxer = checkProg('a LyX -> HTML converter',
685 ['elyxer.py --directory $$r $$i $$o', 'elyxer --directory $$r $$i $$o'],
686 rc_entry = [ r'\converter lyx html "%%" ""' ])
687 path, elyxer = checkProg('a LyX -> HTML (MS Word) converter',
688 ['elyxer.py --html --directory $$r $$i $$o', 'elyxer --html --directory $$r $$i $$o'],
689 rc_entry = [ r'\converter lyx wordhtml "%%" ""' ])
690 if elyxer.find('elyxer') >= 0:
691 addToRC(r'''\copier html "python -tt $$s/scripts/ext_copy.py -e html,png,jpg,jpeg,css $$i $$o"''')
692 addToRC(r'''\copier wordhtml "python -tt $$s/scripts/ext_copy.py -e html,png,jpg,jpeg,css $$i $$o"''')
694 # search for HTML converters other than eLyXer
695 # On SuSE the scripts have a .sh suffix, and on debian they are in /usr/share/tex4ht/
696 path, htmlconv = checkProg('a LaTeX -> HTML converter', ['htlatex $$i', 'htlatex.sh $$i', \
697 '/usr/share/tex4ht/htlatex $$i', 'tth -t -e2 -L$$b < $$i > $$o', \
698 'latex2html -no_subdir -split 0 -show_section_numbers $$i', 'hevea -s $$i'],
699 rc_entry = [ r'\converter latex html "%%" "needaux"' ])
700 if htmlconv.find('htlatex') >= 0 or htmlconv == 'latex2html':
701 addToRC(r'''\copier html "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
703 addToRC(r'''\copier html "python -tt $$s/scripts/ext_copy.py $$i $$o"''')
704 path, htmlconv = checkProg('a LaTeX -> HTML (MS Word) converter', ["htlatex $$i 'html,word' 'symbol/!' '-cvalidate'", \
705 "htlatex.sh $$i 'html,word' 'symbol/!' '-cvalidate'", \
706 "/usr/share/tex4ht/htlatex $$i 'html,word' 'symbol/!' '-cvalidate'"],
707 rc_entry = [ r'\converter latex wordhtml "%%" "needaux"' ])
708 if htmlconv.find('htlatex') >= 0:
709 addToRC(r'''\copier wordhtml "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
711 addToRC(r'''\copier wordhtml "python -tt $$s/scripts/ext_copy.py $$i $$o"''')
714 # Check if LyXBlogger is installed
715 lyxblogger_found = checkModule('lyxblogger')
717 addToRC(r'\Format blog blog "LyXBlogger" "" "" "" "document"')
718 addToRC(r'\converter xhtml blog "python -m lyxblogger $$i" ""')
721 checkProg('an OpenOffice.org -> LaTeX converter', ['w2l -clean $$i'],
722 rc_entry = [ r'\converter sxw latex "%%" ""' ])
724 checkProg('an OpenDocument -> LaTeX converter', ['w2l -clean $$i'],
725 rc_entry = [ r'\converter odt latex "%%" ""' ])
726 # According to http://www.tug.org/applications/tex4ht/mn-commands.html
727 # the command mk4ht oolatex $$i has to be used as default,
728 # but as this would require to have Perl installed, in MiKTeX oolatex is
729 # directly available as application.
730 # On SuSE the scripts have a .sh suffix, and on debian they are in /usr/share/tex4ht/
731 # Both SuSE and debian have oolatex
732 checkProg('a LaTeX -> Open Document converter', [
733 'oolatex $$i', 'mk4ht oolatex $$i', 'oolatex.sh $$i', '/usr/share/tex4ht/oolatex $$i',
734 'htlatex $$i \'xhtml,ooffice\' \'ooffice/! -cmozhtf\' \'-coo\' \'-cvalidate\''],
735 rc_entry = [ r'\converter latex odt "%%" "needaux"' ])
736 # On windows it is called latex2rt.exe
737 checkProg('a LaTeX -> RTF converter', ['latex2rtf -p -S -o $$o $$i', 'latex2rt -p -S -o $$o $$i'],
738 rc_entry = [ r'\converter latex rtf "%%" "needaux"' ])
740 checkProg('a RTF -> HTML converter', ['unrtf --html $$i > $$o'],
741 rc_entry = [ r'\converter rtf html "%%" ""' ])
743 checkProg('a PS to PDF converter', ['ps2pdf13 $$i $$o'],
744 rc_entry = [ r'\converter ps pdf "%%" ""' ])
746 checkProg('a PS to TXT converter', ['pstotext $$i > $$o'],
747 rc_entry = [ r'\converter ps text2 "%%" ""' ])
749 checkProg('a PS to TXT converter', ['ps2ascii $$i $$o'],
750 rc_entry = [ r'\converter ps text3 "%%" ""' ])
752 checkProg('a PS to EPS converter', ['ps2eps $$i'],
753 rc_entry = [ r'\converter ps eps "%%" ""' ])
755 checkProg('a PDF to PS converter', ['pdf2ps $$i $$o', 'pdftops $$i $$o'],
756 rc_entry = [ r'\converter pdf ps "%%" ""' ])
758 checkProg('a PDF to EPS converter', ['pdftops -eps -f 1 -l 1 $$i $$o'],
759 rc_entry = [ r'\converter pdf eps "%%" ""' ])
761 checkProg('a DVI to TXT converter', ['catdvi $$i > $$o'],
762 rc_entry = [ r'\converter dvi text4 "%%" ""' ])
764 checkProg('a DVI to PS converter', ['dvips -o $$o $$i'],
765 rc_entry = [ r'\converter dvi ps "%%" ""' ])
767 checkProg('a DVI to PDF converter', ['dvipdfmx -o $$o $$i', 'dvipdfm -o $$o $$i'],
768 rc_entry = [ r'\converter dvi pdf3 "%%" ""' ])
770 path, dvipng = checkProg('dvipng', ['dvipng'])
771 path, dv2dt = checkProg('DVI to DTL converter', ['dv2dt'])
772 if dvipng == "dvipng" and dv2dt == 'dv2dt':
773 addToRC(r'\converter lyxpreview png "python -tt $$s/scripts/lyxpreview2bitmap.py" ""')
775 # set empty converter to override the default imagemagick
776 addToRC(r'\converter lyxpreview png "" ""')
778 addToRC(r'\converter lyxpreview ppm "python -tt $$s/scripts/lyxpreview2bitmap.py" ""')
780 # set empty converter to override the default imagemagick
781 addToRC(r'\converter lyxpreview ppm "" ""')
783 checkProg('a fax program', ['kdeprintfax $$i', 'ksendfax $$i', 'hylapex $$i'],
784 rc_entry = [ r'\converter ps fax "%%" ""'])
786 path, fig2dev = checkProg('a FIG -> Image converter', ['fig2dev'])
787 if fig2dev == "fig2dev":
788 addToRC(r'''\converter fig eps "fig2dev -L eps $$i $$o" ""
789 \converter fig ppm "fig2dev -L ppm $$i $$o" ""
790 \converter fig png "fig2dev -L png $$i $$o" ""
791 \converter fig pdftex "python -tt $$s/scripts/fig2pdftex.py $$i $$o" ""
792 \converter fig pstex "python -tt $$s/scripts/fig2pstex.py $$i $$o" ""''')
794 checkProg('a TIFF -> PS converter', ['tiff2ps $$i > $$o'],
795 rc_entry = [ r'\converter tiff eps "%%" ""', ''])
797 checkProg('a TGIF -> EPS/PPM converter', ['tgif'],
799 r'''\converter tgif eps "tgif -print -color -eps -stdout $$i > $$o" ""
800 \converter tgif png "tgif -print -color -png -o $$d $$i" ""
801 \converter tgif pdf "tgif -print -color -pdf -stdout $$i > $$o" ""''',
804 checkProg('a WMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i'],
805 rc_entry = [ r'\converter wmf eps "%%" ""'])
807 checkProg('an EMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i'],
808 rc_entry = [ r'\converter emf eps "%%" ""'])
810 checkProg('an EPS -> PDF converter', ['epstopdf'],
811 rc_entry = [ r'\converter eps pdf "epstopdf --outfile=$$o $$i" ""', ''])
813 # no agr -> pdf converter, since the pdf library used by gracebat is not
814 # free software and therefore not compiled in in many installations.
815 # Fortunately, this is not a big problem, because we will use epstopdf to
816 # convert from agr to pdf via eps without loss of quality.
817 checkProg('a Grace -> Image converter', ['gracebat'],
819 r'''\converter agr eps "gracebat -hardcopy -printfile $$o -hdevice EPS $$i 2>/dev/null" ""
820 \converter agr png "gracebat -hardcopy -printfile $$o -hdevice PNG $$i 2>/dev/null" ""
821 \converter agr jpg "gracebat -hardcopy -printfile $$o -hdevice JPEG $$i 2>/dev/null" ""
822 \converter agr ppm "gracebat -hardcopy -printfile $$o -hdevice PNM $$i 2>/dev/null" ""''',
825 checkProg('a Dot -> Image converter', ['dot'],
827 r'''\converter dot eps "dot -Teps $$i -o $$o" ""
828 \converter dot png "dot -Tpng $$i -o $$o" ""''',
831 checkProg('a Dia -> PNG converter', ['dia -e $$o -t png $$i'],
832 rc_entry = [ r'\converter dia png "%%" ""'])
834 checkProg('a Dia -> EPS converter', ['dia -e $$o -t eps $$i'],
835 rc_entry = [ r'\converter dia eps "%%" ""'])
837 checkProg('a SVG -> PDF converter', ['rsvg-convert -f pdf -o $$o $$i', 'inkscape --file=$$p/$$i --export-area-drawing --without-gui --export-pdf=$$p/$$o'],
838 rc_entry = [ r'\converter svg pdf "%%" ""'])
840 checkProg('a SVG -> EPS converter', ['rsvg-convert -f ps -o $$o $$i', 'inkscape --file=$$p/$$i --export-area-drawing --without-gui --export-eps=$$p/$$o'],
841 rc_entry = [ r'\converter svg eps "%%" ""'])
842 # the PNG export via Inkscape must not have the full path ($$p) for the file
843 checkProg('a SVG -> PNG converter', ['rsvg-convert -f png -o $$o $$i', 'inkscape --without-gui --file=$$i --export-png=$$o'],
844 rc_entry = [ r'\converter svg png "%%" ""'])
847 # gnumeric/xls/ods to tex
848 checkProg('a spreadsheet -> latex converter', ['ssconvert'],
849 rc_entry = [ r'''\converter gnumeric latex "ssconvert --export-type=Gnumeric_html:latex $$i $$o" ""
850 \converter ods latex "ssconvert --export-type=Gnumeric_html:latex $$i $$o" ""
851 \converter xls latex "ssconvert --export-type=Gnumeric_html:latex $$i $$o" ""''',
854 path, lilypond = checkProg('a LilyPond -> EPS/PDF/PNG converter', ['lilypond'])
856 version_string = cmdOutput("lilypond --version")
857 match = re.match('GNU LilyPond (\S+)', version_string)
859 version_number = match.groups()[0]
860 version = version_number.split('.')
861 if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 11):
862 addToRC(r'''\converter lilypond eps "lilypond -dbackend=eps -dsafe --ps $$i" ""
863 \converter lilypond png "lilypond -dbackend=eps -dsafe --png $$i" ""''')
864 addToRC(r'\converter lilypond pdf "lilypond -dbackend=eps -dsafe --pdf $$i" ""')
865 logger.info('+ found LilyPond version %s.' % version_number)
866 elif int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 6):
867 addToRC(r'''\converter lilypond eps "lilypond -b eps --ps --safe $$i" ""
868 \converter lilypond png "lilypond -b eps --png $$i" ""''')
869 if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 9):
870 addToRC(r'\converter lilypond pdf "lilypond -b eps --pdf --safe $$i" ""')
871 logger.info('+ found LilyPond version %s.' % version_number)
873 logger.info('+ found LilyPond, but version %s is too old.' % version_number)
875 logger.info('+ found LilyPond, but could not extract version number.')
877 path, lilypond_book = checkProg('a LilyPond book (LaTeX) -> LaTeX converter', ['lilypond-book'])
878 if (lilypond_book != ''):
879 version_string = cmdOutput("lilypond-book --version")
880 match = re.match('^(\S+)$', version_string)
882 version_number = match.groups()[0]
883 version = version_number.split('.')
884 if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 13):
886 addToRC(r'\converter lyxpreview-lytex ppm "python -tt $$s/scripts/lyxpreview-lytex2bitmap.py" ""')
888 # set empty converter to override the default imagemagick
889 addToRC(r'\converter lyxpreview-lytex ppm "" ""')
890 if dvipng == "dvipng" and dv2dt == 'dv2dt':
891 addToRC(r'\converter lyxpreview-lytex png "python -tt $$s/scripts/lyxpreview-lytex2bitmap.py" ""')
893 # set empty converter to override the default imagemagick
894 addToRC(r'\converter lyxpreview-lytex png "" ""')
895 # Note: The --lily-output-dir flag is required because lilypond-book
896 # does not process input again unless the input has changed,
897 # even if the output format being requested is different. So
898 # once a .eps file exists, lilypond-book won't create a .pdf
899 # even when requested with --pdf. This is a problem if a user
900 # clicks View PDF after having done a View DVI. To circumvent
901 # this, use different output folders for eps and pdf outputs.
902 addToRC(r'\converter lilypond-book latex "lilypond-book --safe --lily-output-dir=ly-eps $$i" ""')
903 addToRC(r'\converter lilypond-book pdflatex "lilypond-book --safe --pdf --latex-program=pdflatex --lily-output-dir=ly-pdf $$i" ""')
904 addToRC(r'\converter lilypond-book xetex "lilypond-book --safe --pdf --latex-program=xelatex --lily-output-dir=ly-pdf $$i" ""')
905 addToRC(r'\converter lilypond-book luatex "lilypond-book --safe --pdf --latex-program=lualatex --lily-output-dir=ly-pdf $$i" ""')
906 logger.info('+ found LilyPond-book version %s.' % version_number)
908 logger.info('+ found LilyPond-book, but version %s is too old.' % version_number)
910 logger.info('+ found LilyPond-book, but could not extract version number.')
912 checkProg('a Noteedit -> LilyPond converter', ['noteedit --export-lilypond $$i'],
913 rc_entry = [ r'\converter noteedit lilypond "%%" ""', ''])
915 # Currently, lyxpak outputs a gzip compressed tar archive on *nix
916 # and a zip archive on Windows.
917 # So, we configure the appropriate version according to the platform.
918 cmd = r'\converter lyx %s "python -tt $$s/scripts/lyxpak.py $$r/$$i" ""'
920 addToRC(r'\Format lyxzip zip "LyX Archive (zip)" "" "" "" "document,menu=export"')
921 addToRC(cmd % "lyxzip")
923 addToRC(r'\Format lyxgz gz "LyX Archive (tar.gz)" "" "" "" "document,menu=export"')
924 addToRC(cmd % "lyxgz")
927 # FIXME: no rc_entry? comment it out
928 # checkProg('Image converter', ['convert $$i $$o'])
930 # Entries that do not need checkProg
931 addToRC(r'''\converter lyxpreview-platex ppm "python -tt $$s/scripts/lyxpreview-platex2bitmap.py" ""
932 \converter csv lyx "python -tt $$s/scripts/csv2lyx.py $$i $$o" ""
933 \converter date dateout "python -tt $$s/scripts/date.py %d-%m-%Y > $$o" ""
934 \converter docbook docbook-xml "cp $$i $$o" "xml"
935 \converter fen asciichess "python -tt $$s/scripts/fen2ascii.py $$i $$o" ""
936 \converter lyx lyx13x "python -tt $$s/lyx2lyx/lyx2lyx -t 221 $$i > $$o" ""
937 \converter lyx lyx14x "python -tt $$s/lyx2lyx/lyx2lyx -t 245 $$i > $$o" ""
938 \converter lyx lyx15x "python -tt $$s/lyx2lyx/lyx2lyx -t 276 $$i > $$o" ""
939 \converter lyx lyx16x "python -tt $$s/lyx2lyx/lyx2lyx -t 345 $$i > $$o" ""
940 \converter lyx clyx "python -tt $$s/lyx2lyx/lyx2lyx -c big5 -t 245 $$i > $$o" ""
941 \converter lyx jlyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_jp -t 245 $$i > $$o" ""
942 \converter lyx klyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_kr -t 245 $$i > $$o" ""
943 \converter clyx lyx "python -tt $$s/lyx2lyx/lyx2lyx -c big5 $$i > $$o" ""
944 \converter jlyx lyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_jp $$i > $$o" ""
945 \converter klyx lyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_kr $$i > $$o" ""
950 ''' Check docbook '''
951 path, DOCBOOK = checkProg('SGML-tools 2.x (DocBook), db2x scripts or xsltproc', ['sgmltools', 'db2dvi', 'xsltproc'],
953 r'''\converter docbook dvi "sgmltools -b dvi $$i" ""
954 \converter docbook html "sgmltools -b html $$i" ""''',
955 r'''\converter docbook dvi "db2dvi $$i" ""
956 \converter docbook html "db2html $$i" ""''',
957 r'''\converter docbook dvi "" ""
958 \converter docbook html "" ""''',
959 r'''\converter docbook dvi "" ""
960 \converter docbook html "" ""'''])
963 return ('yes', 'true', '\\def\\hasdocbook{yes}')
965 return ('no', 'false', '')
968 def checkOtherEntries():
969 ''' entries other than Format and Converter '''
970 checkProg('ChkTeX', ['chktex -n1 -n3 -n6 -n9 -n22 -n25 -n30 -n38'],
971 rc_entry = [ r'\chktex_command "%%"' ])
972 checkProgAlternatives('BibTeX or alternative programs', ['bibtex', 'bibtex8', 'biber'],
973 rc_entry = [ r'\bibtex_command "%%"' ],
974 alt_rc_entry = [ r'\bibtex_alternatives "%%"' ])
975 checkProg('a specific Japanese BibTeX variant', ['pbibtex', 'jbibtex', 'bibtex'],
976 rc_entry = [ r'\jbibtex_command "%%"' ])
977 checkProgAlternatives('available index processors', ['texindy', 'makeindex -c -q', 'xindy'],
978 rc_entry = [ r'\index_command "%%"' ],
979 alt_rc_entry = [ r'\index_alternatives "%%"' ])
980 checkProg('an index processor appropriate to Japanese', ['mendex -c -q', 'jmakeindex -c -q', 'makeindex -c -q'],
981 rc_entry = [ r'\jindex_command "%%"' ])
982 path, splitindex = checkProg('the splitindex processor', ['splitindex.pl', 'splitindex'],
983 rc_entry = [ r'\splitindex_command "%%"' ])
985 checkProg('the splitindex processor (java version)', ['splitindex.class'],
986 rc_entry = [ r'\splitindex_command "java splitindex"' ])
987 checkProg('a nomenclature processor', ['makeindex'],
988 rc_entry = [ r'\nomencl_command "makeindex -s nomencl.ist"' ])
989 ## FIXME: OCTAVE is not used anywhere
990 # path, OCTAVE = checkProg('Octave', ['octave'])
991 ## FIXME: MAPLE is not used anywhere
992 # path, MAPLE = checkProg('Maple', ['maple'])
993 checkProg('a spool command', ['lp', 'lpr'],
995 r'''\print_spool_printerprefix "-d "
996 \print_spool_command "lp"''',
997 r'''\print_spool_printerprefix "-P",
998 \print_spool_command "lpr"''',
1000 # Add the rest of the entries (no checkProg is required)
1001 addToRC(r'''\copier fig "python -tt $$s/scripts/fig_copy.py $$i $$o"
1002 \copier pstex "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
1003 \copier pdftex "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
1004 \copier program "python -tt $$s/scripts/ext_copy.py $$i $$o"
1008 def processLayoutFile(file, bool_docbook):
1009 ''' process layout file and get a line of result
1011 Declare lines look like this: (article.layout, scrbook.layout, svjog.layout)
1013 \DeclareLaTeXClass{article}
1014 \DeclareLaTeXClass[scrbook]{book (koma-script)}
1015 \DeclareLaTeXClass[svjour,svjog.clo]{article (Springer - svjour/jog)}
1019 "article" "article" "article" "false" "article.cls"
1020 "scrbook" "scrbook" "book (koma-script)" "false" "scrbook.cls"
1021 "svjog" "svjour" "article (Springer - svjour/jog)" "false" "svjour.cls,svjog.clo"
1023 def checkForClassExtension(x):
1024 '''if the extension for a latex class is not
1025 provided, add .cls to the classname'''
1027 return x.strip() + '.cls'
1030 classname = file.split(os.sep)[-1].split('.')[0]
1031 # return ('LaTeX', '[a,b]', 'a', ',b,c', 'article') for \DeclareLaTeXClass[a,b,c]{article}
1032 p = re.compile(r'\Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}')
1033 for line in open(file).readlines():
1034 res = p.search(line)
1036 (classtype, optAll, opt, opt1, desc) = res.groups()
1037 avai = {'LaTeX':'false', 'DocBook':bool_docbook}[classtype]
1040 prereq_latex = checkForClassExtension(classname)
1042 prereq_list = optAll[1:-1].split(',')
1043 prereq_list = map(checkForClassExtension, prereq_list)
1044 prereq_latex = ','.join(prereq_list)
1045 prereq_docbook = {'true':'', 'false':'docbook'}[bool_docbook]
1046 prereq = {'LaTeX':prereq_latex, 'DocBook':prereq_docbook}[classtype]
1047 return '"%s" "%s" "%s" "%s" "%s"\n' % (classname, opt, desc, avai, prereq)
1048 logger.warning("Layout file " + file + " has no \DeclareXXClass line. ")
1052 def checkLatexConfig(check_config, bool_docbook):
1053 ''' Explore the LaTeX configuration
1054 Return None (will be passed to sys.exit()) for success.
1056 msg = 'checking LaTeX configuration... '
1057 # if --without-latex-config is forced, or if there is no previous
1058 # version of textclass.lst, re-generate a default file.
1059 if not os.path.isfile('textclass.lst') or not check_config:
1060 # remove the files only if we want to regenerate
1061 removeFiles(['textclass.lst', 'packages.lst'])
1063 # Then, generate a default textclass.lst. In case configure.py
1064 # fails, we still have something to start lyx.
1065 logger.info(msg + ' default values')
1066 logger.info('+checking list of textclasses... ')
1067 tx = open('textclass.lst', 'w')
1069 # This file declares layouts and their associated definition files
1070 # (include dir. relative to the place where this file is).
1071 # It contains only default values, since chkconfig.ltx could not be run
1072 # for some reason. Run ./configure.py if you need to update it after a
1073 # configuration change.
1075 # build the list of available layout files and convert it to commands
1078 for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
1079 glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
1081 if not os.path.isfile(file):
1083 # get stuff between /xxxx.layout .
1084 classname = file.split(os.sep)[-1].split('.')[0]
1086 cleanclass = classname.replace(' ', '_')
1087 cleanclass = cleanclass.replace('-', '_')
1088 # make sure the same class is not considered twice
1089 if foundClasses.count(cleanclass) == 0: # not found before
1090 foundClasses.append(cleanclass)
1091 retval = processLayoutFile(file, bool_docbook)
1095 logger.info('\tdone')
1096 if not check_config:
1098 # the following will generate textclass.lst.tmp, and packages.lst.tmp
1099 logger.info(msg + '\tauto')
1100 removeFiles(['wrap_chkconfig.ltx', 'chkconfig.vars', \
1101 'chkconfig.classes', 'chklayouts.tex'])
1103 if not os.path.isfile( 'chkconfig.ltx' ):
1104 shutil.copyfile( os.path.join(srcdir, 'chkconfig.ltx'), 'chkconfig.ltx' )
1106 writeToFile('wrap_chkconfig.ltx', '%s\n\\input{chkconfig.ltx}\n' % docbook_cmd)
1107 # Construct the list of classes to test for.
1108 # build the list of available layout files and convert it to commands
1110 declare = re.compile(r'\Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}')
1111 empty = re.compile(r'^\s*$')
1112 testclasses = list()
1113 for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
1114 glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
1115 nodeclaration = False
1116 if not os.path.isfile(file):
1118 classname = file.split(os.sep)[-1].split('.')[0]
1119 for line in open(file).readlines():
1120 if not empty.match(line) and line[0] != '#':
1121 logger.warning("Failed to find valid \Declare line for layout file `" + file + "'.\n\t=> Skipping this file!")
1122 nodeclaration = True
1124 if declare.search(line) == None:
1126 testclasses.append("\\TestDocClass{%s}{%s}" % (classname, line[1:].strip()))
1131 cl = open('chklayouts.tex', 'w')
1132 for line in testclasses:
1133 cl.write(line + '\n')
1136 # we have chklayouts.tex, then process it
1137 fout = os.popen(LATEX + ' wrap_chkconfig.ltx')
1139 line = fout.readline()
1142 if re.match('^\+', line):
1143 logger.info(line.strip())
1144 # if the command succeeds, None will be returned
1147 # currently, values in chhkconfig are only used to set
1150 for line in open('chkconfig.vars').readlines():
1151 key, val = re.sub('-', '_', line).split('=')
1153 values[key] = val.strip("'")
1154 # chk_fontenc may not exist
1156 addToRC(r'\font_encoding "%s"' % values["chk_fontenc"])
1159 if rmcopy: # remove the copied file
1160 removeFiles( [ 'chkconfig.ltx' ] )
1161 # if configure successed, move textclass.lst.tmp to textclass.lst
1162 # and packages.lst.tmp to packages.lst
1163 if os.path.isfile('textclass.lst.tmp') and len(open('textclass.lst.tmp').read()) > 0 \
1164 and os.path.isfile('packages.lst.tmp') and len(open('packages.lst.tmp').read()) > 0:
1165 shutil.move('textclass.lst.tmp', 'textclass.lst')
1166 shutil.move('packages.lst.tmp', 'packages.lst')
1170 def checkModulesConfig():
1171 removeFiles(['lyxmodules.lst', 'chkmodules.tex'])
1173 logger.info('+checking list of modules... ')
1174 tx = open('lyxmodules.lst', 'w')
1175 tx.write('''## This file declares modules and their associated definition files.
1176 ## It has been automatically generated by configure
1177 ## Use "Options/Reconfigure" if you need to update it after a
1178 ## configuration change.
1179 ## "ModuleName" "filename" "Description" "Packages" "Requires" "Excludes" "Category"
1182 # build the list of available modules
1184 # note that this searches the local directory first, then the
1185 # system directory. that way, we pick up the user's version first.
1186 for file in glob.glob( os.path.join('layouts', '*.module') ) + \
1187 glob.glob( os.path.join(srcdir, 'layouts', '*.module' ) ) :
1190 if not os.path.isfile(file):
1193 filename = file.split(os.sep)[-1]
1194 filename = filename[:-7]
1195 if seen.count(filename):
1198 seen.append(filename)
1199 retval = processModuleFile(file, filename, bool_docbook)
1203 logger.info('\tdone')
1206 def processModuleFile(file, filename, bool_docbook):
1207 ''' process module file and get a line of result
1209 The top of a module file should look like this:
1210 #\DeclareLyXModule[LaTeX Packages]{ModuleName}
1212 #...body of description...
1214 #Requires: [list of required modules]
1215 #Excludes: [list of excluded modules]
1216 #Category: [category name]
1217 The last three lines are optional (though do give a category).
1219 "ModuleName" "filename" "Description" "Packages" "Requires" "Excludes" "Category"
1221 remods = re.compile(r'\DeclareLyXModule\s*(?:\[([^]]*?)\])?{(.*)}')
1222 rereqs = re.compile(r'#+\s*Requires: (.*)')
1223 reexcs = re.compile(r'#+\s*Excludes: (.*)')
1224 recaty = re.compile(r'#+\s*Category: (.*)')
1225 redbeg = re.compile(r'#+\s*DescriptionBegin\s*$')
1226 redend = re.compile(r'#+\s*DescriptionEnd\s*$')
1228 modname = desc = pkgs = req = excl = catgy = ""
1229 readingDescription = False
1232 for line in open(file).readlines():
1233 if readingDescription:
1234 res = redend.search(line)
1236 readingDescription = False
1237 desc = " ".join(descLines)
1239 desc = desc.replace('"', '\\"')
1241 descLines.append(line[1:].strip())
1243 res = redbeg.search(line)
1245 readingDescription = True
1247 res = remods.search(line)
1249 (pkgs, modname) = res.groups()
1253 tmp = [s.strip() for s in pkgs.split(",")]
1254 pkgs = ",".join(tmp)
1256 res = rereqs.search(line)
1259 tmp = [s.strip() for s in req.split("|")]
1262 res = reexcs.search(line)
1265 tmp = [s.strip() for s in excl.split("|")]
1266 excl = "|".join(tmp)
1268 res = recaty.search(line)
1270 catgy = res.group(1)
1274 logger.warning("Module file without \DeclareLyXModule line. ")
1278 # this module has some latex dependencies:
1279 # append the dependencies to chkmodules.tex,
1280 # which is \input'ed by chkconfig.ltx
1281 testpackages = list()
1282 for pkg in pkgs.split(","):
1284 # this is a converter dependency: skip
1286 if pkg.endswith(".sty"):
1288 testpackages.append("\\TestPackage{%s}" % (pkg,))
1289 cm = open('chkmodules.tex', 'a')
1290 for line in testpackages:
1291 cm.write(line + '\n')
1294 return '"%s" "%s" "%s" "%s" "%s" "%s" "%s"\n' % (modname, filename, desc, pkgs, req, excl, catgy)
1298 def checkTeXAllowSpaces():
1299 ''' Let's check whether spaces are allowed in TeX file names '''
1300 tex_allows_spaces = 'false'
1301 if lyx_check_config:
1302 msg = "Checking whether TeX allows spaces in file names... "
1303 writeToFile('a b.tex', r'\message{working^^J}' )
1305 if os.name == 'nt' or sys.platform == 'cygwin':
1306 latex_out = cmdOutput(LATEX + r""" "\nonstopmode\input{\"a b\"}" """)
1307 if not 'working' in latex_out:
1308 latex_out = cmdOutput(LATEX + r' "\nonstopmode\input{a b}"')
1310 latex_out = cmdOutput(LATEX + r""" '\nonstopmode\input{"a b"}' """)
1313 if 'working' in latex_out:
1314 logger.info(msg + 'yes')
1315 tex_allows_spaces = 'true'
1317 logger.info(msg + 'no')
1318 tex_allows_spaces = 'false'
1319 addToRC(r'\tex_allows_spaces ' + tex_allows_spaces)
1320 removeFiles( [ 'a b.tex', 'a b.log', 'texput.log' ])
1323 def removeTempFiles():
1325 if not lyx_keep_temps:
1326 removeFiles(['chkconfig.vars', \
1327 'wrap_chkconfig.ltx', 'wrap_chkconfig.log', \
1328 'chklayouts.tex', 'chkmodules.tex', 'missfont.log',
1329 'chklatex.ltx', 'chklatex.log'])
1332 if __name__ == '__main__':
1333 lyx_check_config = True
1334 outfile = 'lyxrc.defaults'
1336 lyx_keep_temps = False
1338 ## Parse the command line
1339 for op in sys.argv[1:]: # default shell/for list is $*, the options
1340 if op in [ '-help', '--help', '-h' ]:
1341 print '''Usage: configure [options]
1343 --help show this help lines
1344 --keep-temps keep temporary files (for debug. purposes)
1345 --without-latex-config do not run LaTeX to determine configuration
1346 --with-version-suffix=suffix suffix of binary installed files
1349 elif op == '--without-latex-config':
1350 lyx_check_config = False
1351 elif op == '--keep-temps':
1352 lyx_keep_temps = True
1353 elif op[0:22] == '--with-version-suffix=': # never mind if op is not long enough
1354 version_suffix = op[22:]
1356 print "Unknown option", op
1359 # check if we run from the right directory
1360 srcdir = os.path.dirname(sys.argv[0])
1363 if not os.path.isfile( os.path.join(srcdir, 'chkconfig.ltx') ):
1364 logger.error("configure: error: cannot find chkconfig.ltx script")
1368 dtl_tools = checkDTLtools()
1369 ## Write the first part of outfile
1370 writeToFile(outfile, '''# This file has been automatically generated by LyX' lib/configure.py
1371 # script. It contains default settings that have been determined by
1372 # examining your system. PLEASE DO NOT MODIFY ANYTHING HERE! If you
1373 # want to customize LyX, use LyX' Preferences dialog or modify directly
1374 # the "preferences" file instead. Any setting in that file will
1375 # override the values given here.
1378 LATEX = checkLatex(dtl_tools)
1379 checkFormatEntries(dtl_tools)
1380 checkConverterEntries()
1381 (chk_docbook, bool_docbook, docbook_cmd) = checkDocBook()
1382 checkTeXAllowSpaces()
1383 windows_style_tex_paths = checkTeXPaths()
1384 if windows_style_tex_paths != '':
1385 addToRC(r'\tex_expects_windows_paths %s' % windows_style_tex_paths)
1387 checkModulesConfig()
1388 # --without-latex-config can disable lyx_check_config
1389 ret = checkLatexConfig(lyx_check_config and LATEX != '', bool_docbook)
1391 # The return error code can be 256. Because most systems expect an error code
1392 # in the range 0-127, 256 can be interpretted as 'success'. Because we expect
1393 # a None for success, 'ret is not None' is used to exit.
1394 sys.exit(ret is not None)