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 shortlen = GetShortPathName(longname, 0, 0)
109 shortname = create_unicode_buffer(shortlen)
110 if GetShortPathName(longname, shortname, shortlen):
111 inpname = shortname.value.replace('\\', '/')
113 inpname = tmpfname.replace('\\', '/')
115 inpname = cmdOutput('cygpath -m ' + tmpfname)
116 logname = os.path.basename(inpname.replace('.ltx', '.log'))
117 inpname = inpname.replace('~', '\\string~')
118 os.write(fd, r'\relax')
120 latex_out = cmdOutput(r'latex "\nonstopmode\input{%s}"' % inpname)
121 if 'Error' in latex_out:
122 latex_out = cmdOutput(r'latex "\nonstopmode\input{\"%s\"}"' % inpname)
123 if 'Error' in latex_out:
124 logger.warning("configure: TeX engine needs posix-style paths in latex files")
125 windows_style_tex_paths = 'false'
127 logger.info("configure: TeX engine needs windows-style paths in latex files")
128 windows_style_tex_paths = 'true'
129 removeFiles([tmpfname, logname, 'texput.log'])
130 return windows_style_tex_paths
133 ## Searching some useful programs
134 def checkProg(description, progs, rc_entry = [], path = [], not_found = ''):
136 This function will search a program in $PATH plus given path
137 If found, return directory and program name (not the options).
139 description: description of the program
141 progs: check programs, for each prog, the first word is used
142 for searching but the whole string is used to replace
143 %% for a rc_entry. So, feel free to add '$$i' etc for programs.
145 path: additional pathes
147 rc_entry: entry to outfile, can be
148 1. emtpy: no rc entry will be added
149 2. one pattern: %% will be replaced by the first found program,
150 or '' if no program is found.
151 3. several patterns for each prog and not_found. This is used
152 when different programs have different usages. If you do not
153 want not_found entry to be added to the RC file, you can specify
154 an entry for each prog and use '' for the not_found entry.
156 not_found: the value that should be used instead of '' if no program
160 # one rc entry for each progs plus not_found entry
161 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
162 logger.error("rc entry should have one item or item for each prog and not_found.")
164 logger.info('checking for ' + description + '...')
165 ## print '(' + ','.join(progs) + ')',
166 for idx in range(len(progs)):
167 # ac_prog may have options, ac_word is the command name
169 ac_word = ac_prog.split(' ')[0]
170 msg = '+checking for "' + ac_word + '"... '
171 path = os.environ["PATH"].split(os.pathsep) + path
173 if "PATHEXT" in os.environ:
174 extlist = extlist + os.environ["PATHEXT"].split(os.pathsep)
177 if os.path.isfile( os.path.join(ac_dir, ac_word + ext) ):
178 logger.info(msg + ' yes')
179 # write rc entries for this command
180 if len(rc_entry) == 1:
181 addToRC(rc_entry[0].replace('%%', ac_prog))
182 elif len(rc_entry) > 1:
183 addToRC(rc_entry[idx].replace('%%', ac_prog))
184 return [ac_dir, ac_word]
186 logger.info(msg + ' no')
187 # write rc entries for 'not found'
188 if len(rc_entry) > 0: # the last one.
189 addToRC(rc_entry[-1].replace('%%', not_found))
190 return ['', not_found]
193 def checkProgAlternatives(description, progs, rc_entry = [], alt_rc_entry = [], path = [], not_found = ''):
195 The same as checkProg, but additionally, all found programs will be added
198 # one rc entry for each progs plus not_found entry
199 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
200 logger.error("rc entry should have one item or item for each prog and not_found.")
202 logger.info('checking for ' + description + '...')
203 ## print '(' + ','.join(progs) + ')',
206 real_ac_word = not_found
207 for idx in range(len(progs)):
208 # ac_prog may have options, ac_word is the command name
210 ac_word = ac_prog.split(' ')[0]
211 msg = '+checking for "' + ac_word + '"... '
212 path = os.environ["PATH"].split(os.pathsep) + path
214 if "PATHEXT" in os.environ:
215 extlist = extlist + os.environ["PATHEXT"].split(os.pathsep)
219 if os.path.isfile( os.path.join(ac_dir, ac_word + ext) ):
220 logger.info(msg + ' yes')
221 pr = re.compile(r'(\\\S+)(.*)$')
223 # write rc entries for this command
224 if found_prime == False:
225 if len(rc_entry) == 1:
226 addToRC(rc_entry[0].replace('%%', ac_prog))
227 elif len(rc_entry) > 1:
228 addToRC(rc_entry[idx].replace('%%', ac_prog))
230 real_ac_word = ac_word
232 if len(alt_rc_entry) == 1:
233 alt_rc = alt_rc_entry[0]
235 # if no explicit alt_rc is given, construct one
236 m = pr.match(rc_entry[0])
238 alt_rc = m.group(1) + "_alternatives" + m.group(2)
239 addToRC(alt_rc.replace('%%', ac_prog))
240 elif len(alt_rc_entry) > 1:
241 alt_rc = alt_rc_entry[idx]
243 # if no explicit alt_rc is given, construct one
244 m = pr.match(rc_entry[idx])
246 alt_rc = m.group(1) + "_alternatives" + m.group(2)
247 addToRC(alt_rc.replace('%%', ac_prog))
252 if found_alt == False:
254 logger.info(msg + ' no')
256 return [real_ac_dir, real_ac_word]
257 # write rc entries for 'not found'
258 if len(rc_entry) > 0: # the last one.
259 addToRC(rc_entry[-1].replace('%%', not_found))
260 return ['', not_found]
263 def addAlternatives(rcs, alt_type):
265 Returns a \\prog_alternatives string to be used as an alternative
266 rc entry. alt_type can be a string or a list of strings.
268 r = re.compile(r'\\Format (\S+).*$')
271 alt_token = '\\%s_alternatives '
272 if isinstance(alt_type, str):
273 alt_tokens = [alt_token % alt_type]
275 alt_tokens = map(lambda s: alt_token % s, alt_type)
276 for idxx in range(len(rcs)):
280 alt = '\n'.join([s + m.group(1) + " %%" for s in alt_tokens])
282 m = r.match(rcs[idxx])
286 alt += '\n'.join([s + m.group(1) + " %%" for s in alt_tokens])
290 def listAlternatives(progs, alt_type, rc_entry = []):
292 Returns a list of \\prog_alternatives strings to be used as alternative
293 rc entries. alt_type can be a string or a list of strings.
295 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
296 logger.error("rc entry should have one item or item for each prog and not_found.")
299 for idx in range(len(progs)):
300 if len(rc_entry) == 1:
301 rcs = rc_entry[0].split('\n')
302 alt = addAlternatives(rcs, alt_type)
303 alt_rc_entry.insert(0, alt)
304 elif len(rc_entry) > 1:
305 rcs = rc_entry[idx].split('\n')
306 alt = addAlternatives(rcs, alt_type)
307 alt_rc_entry.insert(idx, alt)
311 def checkViewer(description, progs, rc_entry = [], path = []):
312 ''' The same as checkProgAlternatives, but for viewers '''
313 alt_rc_entry = listAlternatives(progs, 'viewer', rc_entry)
314 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
317 def checkEditor(description, progs, rc_entry = [], path = []):
318 ''' The same as checkProgAlternatives, but for editors '''
319 alt_rc_entry = listAlternatives(progs, 'editor', rc_entry)
320 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
323 def checkViewerNoRC(description, progs, rc_entry = [], path = []):
324 ''' The same as checkViewer, but do not add rc entry '''
325 alt_rc_entry = listAlternatives(progs, 'viewer', rc_entry)
327 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
330 def checkEditorNoRC(description, progs, rc_entry = [], path = []):
331 ''' The same as checkViewer, but do not add rc entry '''
332 alt_rc_entry = listAlternatives(progs, 'editor', rc_entry)
334 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
337 def checkViewerEditor(description, progs, rc_entry = [], path = []):
338 ''' The same as checkProgAlternatives, but for viewers and editors '''
339 alt_rc_entry = listAlternatives(progs, ['editor', 'viewer'], rc_entry)
340 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
344 ''' Check whether DTL tools are available (Windows only) '''
345 # Find programs! Returned path is not used now
346 if ((os.name == 'nt' or sys.platform == 'cygwin') and
347 checkProg('DVI to DTL converter', ['dv2dt']) != ['', ''] and
348 checkProg('DTL to DVI converter', ['dt2dv']) != ['', '']):
355 def checkLatex(dtl_tools):
356 ''' Check latex, return lyx_check_config '''
357 path, LATEX = checkProg('a Latex2e program', ['latex $$i', 'latex2e $$i'])
358 path, PPLATEX = checkProg('a DVI postprocessing program', ['pplatex $$i'])
359 #-----------------------------------------------------------------
360 path, PLATEX = checkProg('pLaTeX, the Japanese LaTeX', ['platex $$i'])
362 # check if PLATEX is pLaTeX2e
363 writeToFile('chklatex.ltx', '''
367 # run platex on chklatex.ltx and check result
368 if cmdOutput(PLATEX + ' chklatex.ltx').find('pLaTeX2e') != -1:
369 # We have the Japanese pLaTeX2e
370 addToRC(r'\converter platex dvi "%s" "latex=platex"' % PLATEX)
373 removeFiles(['chklatex.ltx', 'chklatex.log'])
374 #-----------------------------------------------------------------
375 # use LATEX to convert from latex to dvi if PPLATEX is not available
379 # Windows only: DraftDVI
380 addToRC(r'''\converter latex dvi2 "%s" "latex"
381 \converter dvi2 dvi "python -tt $$s/scripts/clean_dvi.py $$i $$o" ""''' % PPLATEX)
383 addToRC(r'\converter latex dvi "%s" "latex"' % PPLATEX)
386 # Check if latex is usable
387 writeToFile('chklatex.ltx', '''
388 \\nonstopmode\\makeatletter
389 \\ifx\\undefined\\documentclass\\else
390 \\message{ThisIsLaTeX2e}
394 # run latex on chklatex.ltx and check result
395 if cmdOutput(LATEX + ' chklatex.ltx').find('ThisIsLaTeX2e') != -1:
399 logger.warning("Latex not usable (not LaTeX2e) ")
400 # remove temporary files
401 removeFiles(['chklatex.ltx', 'chklatex.log'])
406 ''' Check if luatex is there and usable '''
407 path, LUATEX = checkProg('LuaTeX', ['lualatex $$i'])
408 path, DVILUATEX = checkProg('LuaTeX (DVI)', ['dvilualatex $$i'])
410 # luatex binary is there
411 msg = "checking if LuaTeX is usable ..."
412 # Check if luatex is usable
413 writeToFile('luatest.tex', '''
414 \\nonstopmode\\documentclass{minimal}
415 \\usepackage{fontspec}
420 # run lualatex on luatest.tex and check result
421 luatest = cmdOutput(LUATEX + ' luatest.tex')
422 if luatest.find('XeTeX is required to compile this document') != -1:
423 # fontspec/luatex too old! We do not support this version.
424 logger.info(msg + ' no (probably not recent enough)')
425 elif luatest.find('! LaTeX Error: File `fontspec.sty\' not found') != -1:
427 logger.info(msg + ' no (missing fontspec)')
430 logger.info(msg + ' yes')
431 addToRC(r'\converter luatex pdf5 "%s" "latex=lualatex"' % LUATEX)
433 addToRC(r'\converter luatex dvi3 "%s" "latex=dvilualatex"' % DVILUATEX)
434 # remove temporary files
435 removeFiles(['luatest.tex', 'luatest.log', 'luatest.aux', 'luatest.pdf'])
438 def checkModule(module):
439 ''' Check for a Python module, return the status '''
440 msg = 'checking for "' + module + ' module"... '
443 logger.info(msg + ' yes')
446 logger.info(msg + ' no')
450 def checkFormatEntries(dtl_tools):
451 ''' Check all formats (\Format entries) '''
452 checkViewerEditor('a Tgif viewer and editor', ['tgif'],
453 rc_entry = [r'\Format tgif obj Tgif "" "%%" "%%" "vector"'])
455 checkViewerEditor('a FIG viewer and editor', ['xfig', 'jfig3-itext.jar', 'jfig3.jar'],
456 rc_entry = [r'\Format fig fig FIG "" "%%" "%%" "vector"'])
458 checkViewerEditor('a Dia viewer and editor', ['dia'],
459 rc_entry = [r'\Format dia dia DIA "" "%%" "%%" "vector"'])
461 checkViewerEditor('a Grace viewer and editor', ['xmgrace'],
462 rc_entry = [r'\Format agr agr Grace "" "%%" "%%" "vector"'])
464 checkViewerEditor('a FEN viewer and editor', ['xboard -lpf $$i -mode EditPosition'],
465 rc_entry = [r'\Format fen fen FEN "" "%%" "%%" ""'])
467 checkViewerEditor('a SVG viewer and editor', ['inkscape'],
468 rc_entry = [r'\Format svg svg SVG "" "%%" "%%" "vector"'])
470 path, iv = checkViewerNoRC('a raster image viewer', ['xv', 'kview', 'gimp-remote', 'gimp'],
471 rc_entry = [r'''\Format bmp bmp BMP "" "%s" "%s" ""
472 \Format gif gif GIF "" "%s" "%s" ""
473 \Format jpg jpg JPEG "" "%s" "%s" ""
474 \Format pbm pbm PBM "" "%s" "%s" ""
475 \Format pgm pgm PGM "" "%s" "%s" ""
476 \Format png png PNG "" "%s" "%s" ""
477 \Format ppm ppm PPM "" "%s" "%s" ""
478 \Format tiff tif TIFF "" "%s" "%s" ""
479 \Format xbm xbm XBM "" "%s" "%s" ""
480 \Format xpm xpm XPM "" "%s" "%s" ""'''])
481 path, ie = checkEditorNoRC('a raster image editor', ['gimp-remote', 'gimp'],
482 rc_entry = [r'''\Format bmp bmp BMP "" "%s" "%s" ""
483 \Format gif gif GIF "" "%s" "%s" ""
484 \Format jpg jpg JPEG "" "%s" "%s" ""
485 \Format pbm pbm PBM "" "%s" "%s" ""
486 \Format pgm pgm PGM "" "%s" "%s" ""
487 \Format png png PNG "" "%s" "%s" ""
488 \Format ppm ppm PPM "" "%s" "%s" ""
489 \Format tiff tif TIFF "" "%s" "%s" ""
490 \Format xbm xbm XBM "" "%s" "%s" ""
491 \Format xpm xpm XPM "" "%s" "%s" ""'''])
492 addToRC(r'''\Format bmp bmp BMP "" "%s" "%s" ""
493 \Format gif gif GIF "" "%s" "%s" ""
494 \Format jpg jpg JPEG "" "%s" "%s" ""
495 \Format pbm pbm PBM "" "%s" "%s" ""
496 \Format pgm pgm PGM "" "%s" "%s" ""
497 \Format png png PNG "" "%s" "%s" ""
498 \Format ppm ppm PPM "" "%s" "%s" ""
499 \Format tiff tif TIFF "" "%s" "%s" ""
500 \Format xbm xbm XBM "" "%s" "%s" ""
501 \Format xpm xpm XPM "" "%s" "%s" ""''' % \
502 (iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie) )
504 checkViewerEditor('a text editor', ['xemacs', 'gvim', 'kedit', 'kwrite', 'kate', \
505 'nedit', 'gedit', 'notepad'],
506 rc_entry = [r'''\Format asciichess asc "Plain text (chess output)" "" "" "%%" ""
507 \Format asciiimage asc "Plain text (image)" "" "" "%%" ""
508 \Format asciixfig asc "Plain text (Xfig output)" "" "" "%%" ""
509 \Format dateout tmp "date (output)" "" "" "%%" ""
510 \Format docbook sgml DocBook B "" "%%" "document,menu=export"
511 \Format docbook-xml xml "DocBook (XML)" "" "" "%%" "document,menu=export"
512 \Format dot dot "Graphviz Dot" "" "" "%%" "vector"
513 \Format platex tex "LaTeX (pLaTeX)" "" "" "%%" "document,menu=export"
514 \Format literate nw NoWeb N "" "%%" "document,menu=export"
515 \Format sweave Rnw "Sweave" S "" "%%" "document,menu=export"
516 \Format r R "R/S code" "" "" "%%" "document,menu=export"
517 \Format lilypond ly "LilyPond music" "" "" "%%" "vector"
518 \Format lilypond-book lytex "LilyPond book (LaTeX)" "" "" "%%" "document,menu=export"
519 \Format latex tex "LaTeX (plain)" L "" "%%" "document,menu=export"
520 \Format luatex tex "LaTeX (LuaTeX)" "" "" "%%" "document,menu=export"
521 \Format pdflatex tex "LaTeX (pdflatex)" "" "" "%%" "document,menu=export"
522 \Format xetex tex "LaTeX (XeTeX)" "" "" "%%" "document,menu=export"
523 \Format text txt "Plain text" a "" "%%" "document,menu=export"
524 \Format text2 txt "Plain text (pstotext)" "" "" "%%" "document"
525 \Format text3 txt "Plain text (ps2ascii)" "" "" "%%" "document"
526 \Format text4 txt "Plain text (catdvi)" "" "" "%%" "document"
527 \Format textparagraph txt "Plain Text, Join Lines" "" "" "%%" "document"''' ])
528 #Spreadsheets using ssconvert from gnumeric
529 checkViewer('gnumeric spreadsheet software', ['gnumeric'],
530 rc_entry = [r'''\Format gnumeric gnumeric "Gnumeric spreadsheet" "" "" "%%" "document"
531 \Format excel xls "Excel spreadsheet" "" "" "%%" "document"
532 \Format oocalc ods "OpenOffice spreadsheet" "" "" "%%" "document"'''])
534 path, xhtmlview = checkViewer('an HTML previewer', ['firefox', 'mozilla file://$$p$$i', 'netscape'],
535 rc_entry = [r'\Format xhtml xhtml "LyXHTML" y "%%" "" "document,menu=export"'])
537 addToRC(r'\Format xhtml xhtml "LyXHTML" y "" "" "document,menu=export"')
539 checkEditor('a BibTeX editor', ['jabref', 'JabRef', \
540 'pybliographic', 'bibdesk', 'gbib', 'kbib', \
541 'kbibtex', 'sixpack', 'bibedit', 'tkbibtex' \
542 'xemacs', 'gvim', 'kedit', 'kwrite', 'kate', \
543 'nedit', 'gedit', 'notepad'],
544 rc_entry = [r'''\Format bibtex bib "BibTeX" "" "" "%%" ""''' ])
546 #checkProg('a Postscript interpreter', ['gs'],
547 # rc_entry = [ r'\ps_command "%%"' ])
548 checkViewer('a Postscript previewer', ['kghostview', 'okular', 'evince', 'gv', 'ghostview -swap'],
549 rc_entry = [r'''\Format eps eps EPS "" "%%" "" "vector"
550 \Format ps ps Postscript t "%%" "" "document,vector,menu=export"'''])
551 # for xdg-open issues look here: http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg151818.html
552 checkViewer('a PDF previewer', ['kpdf', 'okular', 'evince', 'kghostview', 'xpdf', 'acrobat', 'acroread', \
554 rc_entry = [r'''\Format pdf pdf "PDF (ps2pdf)" P "%%" "" "document,vector,menu=export"
555 \Format pdf2 pdf "PDF (pdflatex)" F "%%" "" "document,vector,menu=export"
556 \Format pdf3 pdf "PDF (dvipdfm)" m "%%" "" "document,vector,menu=export"
557 \Format pdf4 pdf "PDF (XeTeX)" X "%%" "" "document,vector,menu=export"
558 \Format pdf5 pdf "PDF (LuaTeX)" u "%%" "" "document,vector,menu=export"'''])
560 checkViewer('a DVI previewer', ['xdvi', 'kdvi', 'okular', 'yap', 'dviout -Set=!m'],
561 rc_entry = [r'''\Format dvi dvi DVI D "%%" "" "document,vector,menu=export"
562 \Format dvi3 dvi "DVI (LuaTeX)" V "%%" "" "document,vector,menu=export"'''])
564 # Windows only: DraftDVI
565 addToRC(r'\Format dvi2 dvi DraftDVI "" "" "" "vector"')
567 checkViewer('an HTML previewer', ['firefox', 'mozilla file://$$p$$i', 'netscape'],
568 rc_entry = [r'\Format html html HTML H "%%" "" "document,menu=export"'])
570 checkViewerEditor('Noteedit', ['noteedit'],
571 rc_entry = [r'\Format noteedit not Noteedit "" "%%" "%%" "vector"'])
573 checkViewerEditor('an OpenDocument/OpenOffice viewer', ['swriter', 'oowriter', 'abiword'],
574 rc_entry = [r'''\Format odt odt OpenDocument "" "%%" "%%" "document,vector,menu=export"
575 \Format sxw sxw "OpenOffice.Org (sxw)" "" "" "" "document,vector"'''])
577 checkViewerEditor('a Rich Text and Word viewer', ['swriter', 'oowriter', 'abiword'],
578 rc_entry = [r'''\Format rtf rtf "Rich Text Format" "" "%%" "%%" "document,vector,menu=export"
579 \Format word doc "MS Word" W "%%" "%%" "document,vector,menu=export"'''])
581 # entries that do not need checkProg
582 addToRC(r'''\Format date "" "date command" "" "" "" ""
583 \Format csv csv "Table (CSV)" "" "" "" "document"
584 \Format fax "" Fax "" "" "" "document"
585 \Format lyx lyx LyX "" "" "" ""
586 \Format lyx13x 13.lyx "LyX 1.3.x" "" "" "" "document"
587 \Format lyx14x 14.lyx "LyX 1.4.x" "" "" "" "document"
588 \Format lyx15x 15.lyx "LyX 1.5.x" "" "" "" "document"
589 \Format lyx16x 16.lyx "LyX 1.6.x" "" "" "" "document,menu=export"
590 \Format lyx20x 20.lyx "LyX 2.0.x" "" "" "" "document,menu=export"
591 \Format clyx cjklyx "CJK LyX 1.4.x (big5)" "" "" "" "document"
592 \Format jlyx cjklyx "CJK LyX 1.4.x (euc-jp)" "" "" "" "document"
593 \Format klyx cjklyx "CJK LyX 1.4.x (euc-kr)" "" "" "" "document"
594 \Format lyxpreview lyxpreview "LyX Preview" "" "" "" ""
595 \Format lyxpreview-lytex lyxpreview-lytex "LyX Preview (LilyPond book)" "" "" "" ""
596 \Format lyxpreview-platex lyxpreview-platex "LyX Preview (pLaTeX)" "" "" "" ""
597 \Format pdftex pdftex_t PDFTEX "" "" "" ""
598 \Format program "" Program "" "" "" ""
599 \Format pstex pstex_t PSTEX "" "" "" ""
600 \Format wmf wmf "Windows Metafile" "" "" "" "vector"
601 \Format emf emf "Enhanced Metafile" "" "" "" "vector"
602 \Format wordhtml html "HTML (MS Word)" "" "" "" "document"
606 def checkConverterEntries():
607 ''' Check all converters (\converter entries) '''
608 checkProg('the pdflatex program', ['pdflatex $$i'],
609 rc_entry = [ r'\converter pdflatex pdf2 "%%" "latex=pdflatex"' ])
611 checkProg('XeTeX', ['xelatex $$i'],
612 rc_entry = [ r'\converter xetex pdf4 "%%" "latex=xelatex"' ])
616 ''' If we're running LyX in-place then tex2lyx will be found in
617 ../src/tex2lyx. Add this directory to the PATH temporarily and
619 Use PATH to avoid any problems with paths-with-spaces.
621 path_orig = os.environ["PATH"]
622 os.environ["PATH"] = os.path.join('..', 'src', 'tex2lyx') + \
623 os.pathsep + path_orig
625 # First search for tex2lyx with version suffix (bug 6986)
626 checkProg('a LaTeX/Noweb -> LyX converter', ['tex2lyx' + version_suffix, 'tex2lyx'],
627 rc_entry = [r'''\converter latex lyx "%% -f $$i $$o" ""
628 \converter literate lyx "%% -n -f $$i $$o" ""'''])
630 os.environ["PATH"] = path_orig
633 checkProg('a Noweb -> LaTeX converter', ['noweave -delay -index $$i > $$o'],
634 rc_entry = [r'''\converter literate latex "%%" ""
635 \converter literate pdflatex "%%" ""'''])
637 checkProg('a Sweave -> LaTeX converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxsweave.R $$p$$i $$p$$o $$e $$r'],
638 rc_entry = [r'''\converter sweave latex "%%" ""
639 \converter sweave pdflatex "%%" ""
640 \converter sweave xetex "%%" ""
641 \converter sweave luatex "%%" ""'''])
643 checkProg('a Sweave -> R/S code converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxstangle.R $$i $$e $$r'],
644 rc_entry = [ r'\converter sweave r "%%" ""' ])
646 checkProg('an HTML -> LaTeX converter', ['html2latex $$i', 'gnuhtml2latex $$i', \
647 'htmltolatex -input $$i -output $$o', 'java -jar htmltolatex.jar -input $$i -output $$o'],
648 rc_entry = [ r'\converter html latex "%%" ""' ])
650 checkProg('an MS Word -> LaTeX converter', ['wvCleanLatex $$i $$o'],
651 rc_entry = [ r'\converter word latex "%%" ""' ])
653 # eLyXer: search as an executable (elyxer.py, elyxer)
654 path, elyxer = checkProg('a LyX -> HTML converter',
655 ['elyxer.py --directory $$r $$i $$o', 'elyxer --directory $$r $$i $$o'],
656 rc_entry = [ r'\converter lyx html "%%" ""' ])
657 path, elyxer = checkProg('a LyX -> HTML (MS Word) converter',
658 ['elyxer.py --html --directory $$r $$i $$o', 'elyxer --html --directory $$r $$i $$o'],
659 rc_entry = [ r'\converter lyx wordhtml "%%" ""' ])
660 if elyxer.find('elyxer') >= 0:
661 addToRC(r'''\copier html "python -tt $$s/scripts/ext_copy.py -e html,png,jpg,jpeg,css $$i $$o"''')
662 addToRC(r'''\copier wordhtml "python -tt $$s/scripts/ext_copy.py -e html,png,jpg,jpeg,css $$i $$o"''')
664 # search for HTML converters other than eLyXer
665 # On SuSE the scripts have a .sh suffix, and on debian they are in /usr/share/tex4ht/
666 path, htmlconv = checkProg('a LaTeX -> HTML converter', ['htlatex $$i', 'htlatex.sh $$i', \
667 '/usr/share/tex4ht/htlatex $$i', 'tth -t -e2 -L$$b < $$i > $$o', \
668 'latex2html -no_subdir -split 0 -show_section_numbers $$i', 'hevea -s $$i'],
669 rc_entry = [ r'\converter latex html "%%" "needaux"' ])
670 if htmlconv.find('htlatex') >= 0 or htmlconv == 'latex2html':
671 addToRC(r'''\copier html "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
673 addToRC(r'''\copier html "python -tt $$s/scripts/ext_copy.py $$i $$o"''')
674 path, htmlconv = checkProg('a LaTeX -> HTML (MS Word) converter', ["htlatex $$i 'html,word' 'symbol/!' '-cvalidate'", \
675 "htlatex.sh $$i 'html,word' 'symbol/!' '-cvalidate'", \
676 "/usr/share/tex4ht/htlatex $$i 'html,word' 'symbol/!' '-cvalidate'"],
677 rc_entry = [ r'\converter latex wordhtml "%%" "needaux"' ])
678 if htmlconv.find('htlatex') >= 0:
679 addToRC(r'''\copier wordhtml "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
681 addToRC(r'''\copier wordhtml "python -tt $$s/scripts/ext_copy.py $$i $$o"''')
684 # Check if LyXBlogger is installed
685 lyxblogger_found = checkModule('lyxblogger')
687 addToRC(r'\Format blog blog "LyXBlogger" "" "" "" "document"')
688 addToRC(r'\converter xhtml blog "python -m lyxblogger $$i" ""')
691 checkProg('an OpenOffice.org -> LaTeX converter', ['w2l -clean $$i'],
692 rc_entry = [ r'\converter sxw latex "%%" ""' ])
694 checkProg('an OpenDocument -> LaTeX converter', ['w2l -clean $$i'],
695 rc_entry = [ r'\converter odt latex "%%" ""' ])
696 # According to http://www.tug.org/applications/tex4ht/mn-commands.html
697 # the command mk4ht oolatex $$i has to be used as default,
698 # but as this would require to have Perl installed, in MiKTeX oolatex is
699 # directly available as application.
700 # On SuSE the scripts have a .sh suffix, and on debian they are in /usr/share/tex4ht/
701 # Both SuSE and debian have oolatex
702 checkProg('a LaTeX -> Open Document converter', [
703 'oolatex $$i', 'mk4ht oolatex $$i', 'oolatex.sh $$i', '/usr/share/tex4ht/oolatex $$i',
704 'htlatex $$i \'xhtml,ooffice\' \'ooffice/! -cmozhtf\' \'-coo\' \'-cvalidate\''],
705 rc_entry = [ r'\converter latex odt "%%" "needaux"' ])
706 # On windows it is called latex2rt.exe
707 checkProg('a LaTeX -> RTF converter', ['latex2rtf -p -S -o $$o $$i', 'latex2rt -p -S -o $$o $$i'],
708 rc_entry = [ r'\converter latex rtf "%%" "needaux"' ])
710 checkProg('a RTF -> HTML converter', ['unrtf --html $$i > $$o'],
711 rc_entry = [ r'\converter rtf html "%%" ""' ])
713 checkProg('a PS to PDF converter', ['ps2pdf13 $$i $$o'],
714 rc_entry = [ r'\converter ps pdf "%%" ""' ])
716 checkProg('a PS to TXT converter', ['pstotext $$i > $$o'],
717 rc_entry = [ r'\converter ps text2 "%%" ""' ])
719 checkProg('a PS to TXT converter', ['ps2ascii $$i $$o'],
720 rc_entry = [ r'\converter ps text3 "%%" ""' ])
722 checkProg('a PS to EPS converter', ['ps2eps $$i'],
723 rc_entry = [ r'\converter ps eps "%%" ""' ])
725 checkProg('a PDF to PS converter', ['pdf2ps $$i $$o', 'pdftops $$i $$o'],
726 rc_entry = [ r'\converter pdf ps "%%" ""' ])
728 checkProg('a PDF to EPS converter', ['pdftops -eps -f 1 -l 1 $$i $$o'],
729 rc_entry = [ r'\converter pdf eps "%%" ""' ])
731 checkProg('a DVI to TXT converter', ['catdvi $$i > $$o'],
732 rc_entry = [ r'\converter dvi text4 "%%" ""' ])
734 checkProg('a DVI to PS converter', ['dvips -o $$o $$i'],
735 rc_entry = [ r'\converter dvi ps "%%" ""' ])
737 checkProg('a DVI to PDF converter', ['dvipdfmx -o $$o $$i', 'dvipdfm -o $$o $$i'],
738 rc_entry = [ r'\converter dvi pdf3 "%%" ""' ])
740 path, dvipng = checkProg('dvipng', ['dvipng'])
741 path, dv2dt = checkProg('DVI to DTL converter', ['dv2dt'])
742 if dvipng == "dvipng" and dv2dt == 'dv2dt':
743 addToRC(r'\converter lyxpreview png "python -tt $$s/scripts/lyxpreview2bitmap.py" ""')
745 # set empty converter to override the default imagemagick
746 addToRC(r'\converter lyxpreview png "" ""')
748 addToRC(r'\converter lyxpreview ppm "python -tt $$s/scripts/lyxpreview2bitmap.py" ""')
750 # set empty converter to override the default imagemagick
751 addToRC(r'\converter lyxpreview ppm "" ""')
753 checkProg('a fax program', ['kdeprintfax $$i', 'ksendfax $$i', 'hylapex $$i'],
754 rc_entry = [ r'\converter ps fax "%%" ""'])
756 path, fig2dev = checkProg('a FIG -> Image converter', ['fig2dev'])
757 if fig2dev == "fig2dev":
758 addToRC(r'''\converter fig eps "fig2dev -L eps $$i $$o" ""
759 \converter fig ppm "fig2dev -L ppm $$i $$o" ""
760 \converter fig png "fig2dev -L png $$i $$o" ""
761 \converter fig pdftex "python -tt $$s/scripts/fig2pdftex.py $$i $$o" ""
762 \converter fig pstex "python -tt $$s/scripts/fig2pstex.py $$i $$o" ""''')
764 checkProg('a TIFF -> PS converter', ['tiff2ps $$i > $$o'],
765 rc_entry = [ r'\converter tiff eps "%%" ""', ''])
767 checkProg('a TGIF -> EPS/PPM converter', ['tgif'],
769 r'''\converter tgif eps "tgif -print -color -eps -stdout $$i > $$o" ""
770 \converter tgif png "tgif -print -color -png -o $$d $$i" ""
771 \converter tgif pdf "tgif -print -color -pdf -stdout $$i > $$o" ""''',
774 checkProg('a WMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i'],
775 rc_entry = [ r'\converter wmf eps "%%" ""'])
777 checkProg('an EMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i'],
778 rc_entry = [ r'\converter emf eps "%%" ""'])
780 checkProg('an EPS -> PDF converter', ['epstopdf'],
781 rc_entry = [ r'\converter eps pdf "epstopdf --outfile=$$o $$i" ""', ''])
783 # no agr -> pdf converter, since the pdf library used by gracebat is not
784 # free software and therefore not compiled in in many installations.
785 # Fortunately, this is not a big problem, because we will use epstopdf to
786 # convert from agr to pdf via eps without loss of quality.
787 checkProg('a Grace -> Image converter', ['gracebat'],
789 r'''\converter agr eps "gracebat -hardcopy -printfile $$o -hdevice EPS $$i 2>/dev/null" ""
790 \converter agr png "gracebat -hardcopy -printfile $$o -hdevice PNG $$i 2>/dev/null" ""
791 \converter agr jpg "gracebat -hardcopy -printfile $$o -hdevice JPEG $$i 2>/dev/null" ""
792 \converter agr ppm "gracebat -hardcopy -printfile $$o -hdevice PNM $$i 2>/dev/null" ""''',
795 checkProg('a Dot -> Image converter', ['dot'],
797 r'''\converter dot eps "dot -Teps $$i -o $$o" ""
798 \converter dot png "dot -Tpng $$i -o $$o" ""''',
801 checkProg('a Dia -> PNG converter', ['dia -e $$o -t png $$i'],
802 rc_entry = [ r'\converter dia png "%%" ""'])
804 checkProg('a Dia -> EPS converter', ['dia -e $$o -t eps $$i'],
805 rc_entry = [ r'\converter dia eps "%%" ""'])
807 checkProg('a SVG -> PDF converter', ['rsvg-convert -f pdf -o $$o $$i', 'inkscape --file=$$i --export-area-drawing --without-gui --export-pdf=$$o'],
808 rc_entry = [ r'\converter svg pdf "%%" ""'])
810 checkProg('a SVG -> EPS converter', ['rsvg-convert -f ps -o $$o $$i', 'inkscape --file=$$i --export-area-drawing --without-gui --export-eps=$$o'],
811 rc_entry = [ r'\converter svg eps "%%" ""'])
813 checkProg('a SVG -> PNG converter', ['rsvg-convert -f png -o $$o $$i', 'inkscape --without-gui --file=$$i --export-png=$$o'],
814 rc_entry = [ r'\converter svg png "%%" ""'])
817 # gnumeric/xls/ods to tex
818 checkProg('a spreadsheet -> latex converter', ['ssconvert'],
819 rc_entry = [ r'''\converter gnumeric latex "ssconvert --export-type=Gnumeric_html:latex $$i $$o" ""
820 \converter ods latex "ssconvert --export-type=Gnumeric_html:latex $$i $$o" ""
821 \converter xls latex "ssconvert --export-type=Gnumeric_html:latex $$i $$o" ""''',
824 path, lilypond = checkProg('a LilyPond -> EPS/PDF/PNG converter', ['lilypond'])
826 version_string = cmdOutput("lilypond --version")
827 match = re.match('GNU LilyPond (\S+)', version_string)
829 version_number = match.groups()[0]
830 version = version_number.split('.')
831 if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 11):
832 addToRC(r'''\converter lilypond eps "lilypond -dbackend=eps -dsafe --ps $$i" ""
833 \converter lilypond png "lilypond -dbackend=eps -dsafe --png $$i" ""''')
834 addToRC(r'\converter lilypond pdf "lilypond -dbackend=eps -dsafe --pdf $$i" ""')
835 logger.info('+ found LilyPond version %s.' % version_number)
836 elif int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 6):
837 addToRC(r'''\converter lilypond eps "lilypond -b eps --ps --safe $$i" ""
838 \converter lilypond png "lilypond -b eps --png $$i" ""''')
839 if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 9):
840 addToRC(r'\converter lilypond pdf "lilypond -b eps --pdf --safe $$i" ""')
841 logger.info('+ found LilyPond version %s.' % version_number)
843 logger.info('+ found LilyPond, but version %s is too old.' % version_number)
845 logger.info('+ found LilyPond, but could not extract version number.')
847 path, lilypond_book = checkProg('a LilyPond book (LaTeX) -> LaTeX converter', ['lilypond-book'])
848 if (lilypond_book != ''):
849 version_string = cmdOutput("lilypond-book --version")
850 match = re.match('^(\S+)$', version_string)
852 version_number = match.groups()[0]
853 version = version_number.split('.')
854 if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 13):
856 addToRC(r'\converter lyxpreview-lytex ppm "python -tt $$s/scripts/lyxpreview-lytex2bitmap.py" ""')
858 # set empty converter to override the default imagemagick
859 addToRC(r'\converter lyxpreview-lytex ppm "" ""')
860 if dvipng == "dvipng" and dv2dt == 'dv2dt':
861 addToRC(r'\converter lyxpreview-lytex png "python -tt $$s/scripts/lyxpreview-lytex2bitmap.py" ""')
863 # set empty converter to override the default imagemagick
864 addToRC(r'\converter lyxpreview-lytex png "" ""')
865 # Note: The --lily-output-dir flag is required because lilypond-book
866 # does not process input again unless the input has changed,
867 # even if the output format being requested is different. So
868 # once a .eps file exists, lilypond-book won't create a .pdf
869 # even when requested with --pdf. This is a problem if a user
870 # clicks View PDF after having done a View DVI. To circumvent
871 # this, use different output folders for eps and pdf outputs.
872 addToRC(r'\converter lilypond-book latex "lilypond-book --safe --lily-output-dir=ly-eps $$i" ""')
873 addToRC(r'\converter lilypond-book pdflatex "lilypond-book --safe --pdf --latex-program=pdflatex --lily-output-dir=ly-pdf $$i" ""')
874 addToRC(r'\converter lilypond-book xetex "lilypond-book --safe --pdf --latex-program=xelatex --lily-output-dir=ly-pdf $$i" ""')
875 addToRC(r'\converter lilypond-book luatex "lilypond-book --safe --pdf --latex-program=lualatex --lily-output-dir=ly-pdf $$i" ""')
876 logger.info('+ found LilyPond-book version %s.' % version_number)
878 logger.info('+ found LilyPond-book, but version %s is too old.' % version_number)
880 logger.info('+ found LilyPond-book, but could not extract version number.')
882 checkProg('a Noteedit -> LilyPond converter', ['noteedit --export-lilypond $$i'],
883 rc_entry = [ r'\converter noteedit lilypond "%%" ""', ''])
885 # Currently, lyxpak outputs a gzip compressed tar archive on *nix
886 # and a zip archive on Windows.
887 # So, we configure the appropriate version according to the platform.
888 cmd = r'\converter lyx %s "python -tt $$s/scripts/lyxpak.py $$r/$$i" ""'
890 addToRC(r'\Format lyxzip zip "LyX Archive (zip)" "" "" "" "document,menu=export"')
891 addToRC(cmd % "lyxzip")
893 addToRC(r'\Format lyxgz gz "LyX Archive (tar.gz)" "" "" "" "document,menu=export"')
894 addToRC(cmd % "lyxgz")
897 # FIXME: no rc_entry? comment it out
898 # checkProg('Image converter', ['convert $$i $$o'])
900 # Entries that do not need checkProg
901 addToRC(r'''\converter lyxpreview-platex ppm "python -tt $$s/scripts/lyxpreview-platex2bitmap.py" ""
902 \converter csv lyx "python -tt $$s/scripts/csv2lyx.py $$i $$o" ""
903 \converter date dateout "python -tt $$s/scripts/date.py %d-%m-%Y > $$o" ""
904 \converter docbook docbook-xml "cp $$i $$o" "xml"
905 \converter fen asciichess "python -tt $$s/scripts/fen2ascii.py $$i $$o" ""
906 \converter lyx lyx13x "python -tt $$s/lyx2lyx/lyx2lyx -t 221 $$i > $$o" ""
907 \converter lyx lyx14x "python -tt $$s/lyx2lyx/lyx2lyx -t 245 $$i > $$o" ""
908 \converter lyx lyx15x "python -tt $$s/lyx2lyx/lyx2lyx -t 276 $$i > $$o" ""
909 \converter lyx lyx16x "python -tt $$s/lyx2lyx/lyx2lyx -t 345 $$i > $$o" ""
910 \converter lyx lyx20x "python -tt $$s/lyx2lyx/lyx2lyx -t 413 $$i > $$o" ""
911 \converter lyx clyx "python -tt $$s/lyx2lyx/lyx2lyx -c big5 -t 245 $$i > $$o" ""
912 \converter lyx jlyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_jp -t 245 $$i > $$o" ""
913 \converter lyx klyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_kr -t 245 $$i > $$o" ""
914 \converter clyx lyx "python -tt $$s/lyx2lyx/lyx2lyx -c big5 $$i > $$o" ""
915 \converter jlyx lyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_jp $$i > $$o" ""
916 \converter klyx lyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_kr $$i > $$o" ""
921 ''' Check docbook '''
922 path, DOCBOOK = checkProg('SGML-tools 2.x (DocBook), db2x scripts or xsltproc', ['sgmltools', 'db2dvi', 'xsltproc'],
924 r'''\converter docbook dvi "sgmltools -b dvi $$i" ""
925 \converter docbook html "sgmltools -b html $$i" ""''',
926 r'''\converter docbook dvi "db2dvi $$i" ""
927 \converter docbook html "db2html $$i" ""''',
928 r'''\converter docbook dvi "" ""
929 \converter docbook html "" ""''',
930 r'''\converter docbook dvi "" ""
931 \converter docbook html "" ""'''])
934 return ('yes', 'true', '\\def\\hasdocbook{yes}')
936 return ('no', 'false', '')
939 def checkOtherEntries():
940 ''' entries other than Format and Converter '''
941 checkProg('ChkTeX', ['chktex -n1 -n3 -n6 -n9 -n22 -n25 -n30 -n38'],
942 rc_entry = [ r'\chktex_command "%%"' ])
943 checkProgAlternatives('BibTeX or alternative programs', ['bibtex', 'bibtex8', 'biber'],
944 rc_entry = [ r'\bibtex_command "%%"' ],
945 alt_rc_entry = [ r'\bibtex_alternatives "%%"' ])
946 checkProg('a specific Japanese BibTeX variant', ['pbibtex', 'jbibtex', 'bibtex'],
947 rc_entry = [ r'\jbibtex_command "%%"' ])
948 checkProgAlternatives('available index processors', ['texindy', 'makeindex -c -q', 'xindy'],
949 rc_entry = [ r'\index_command "%%"' ],
950 alt_rc_entry = [ r'\index_alternatives "%%"' ])
951 checkProg('an index processor appropriate to Japanese', ['mendex -c -q', 'jmakeindex -c -q', 'makeindex -c -q'],
952 rc_entry = [ r'\jindex_command "%%"' ])
953 path, splitindex = checkProg('the splitindex processor', ['splitindex.pl', 'splitindex'],
954 rc_entry = [ r'\splitindex_command "%%"' ])
956 checkProg('the splitindex processor (java version)', ['splitindex.class'],
957 rc_entry = [ r'\splitindex_command "java splitindex"' ])
958 checkProg('a nomenclature processor', ['makeindex'],
959 rc_entry = [ r'\nomencl_command "makeindex -s nomencl.ist"' ])
960 ## FIXME: OCTAVE is not used anywhere
961 # path, OCTAVE = checkProg('Octave', ['octave'])
962 ## FIXME: MAPLE is not used anywhere
963 # path, MAPLE = checkProg('Maple', ['maple'])
964 checkProg('a spool command', ['lp', 'lpr'],
966 r'''\print_spool_printerprefix "-d "
967 \print_spool_command "lp"''',
968 r'''\print_spool_printerprefix "-P",
969 \print_spool_command "lpr"''',
971 # Add the rest of the entries (no checkProg is required)
972 addToRC(r'''\copier fig "python -tt $$s/scripts/fig_copy.py $$i $$o"
973 \copier pstex "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
974 \copier pdftex "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
975 \copier program "python -tt $$s/scripts/ext_copy.py $$i $$o"
979 def processLayoutFile(file, bool_docbook):
980 ''' process layout file and get a line of result
982 Declare lines look like this: (article.layout, scrbook.layout, svjog.layout)
984 \DeclareLaTeXClass{article}
985 \DeclareLaTeXClass[scrbook]{book (koma-script)}
986 \DeclareLaTeXClass[svjour,svjog.clo]{article (Springer - svjour/jog)}
990 "article" "article" "article" "false" "article.cls"
991 "scrbook" "scrbook" "book (koma-script)" "false" "scrbook.cls"
992 "svjog" "svjour" "article (Springer - svjour/jog)" "false" "svjour.cls,svjog.clo"
994 def checkForClassExtension(x):
995 '''if the extension for a latex class is not
996 provided, add .cls to the classname'''
998 return x.strip() + '.cls'
1001 classname = file.split(os.sep)[-1].split('.')[0]
1002 # return ('LaTeX', '[a,b]', 'a', ',b,c', 'article') for \DeclareLaTeXClass[a,b,c]{article}
1003 p = re.compile(r'\Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}')
1004 for line in open(file).readlines():
1005 res = p.search(line)
1007 (classtype, optAll, opt, opt1, desc) = res.groups()
1008 avai = {'LaTeX':'false', 'DocBook':bool_docbook}[classtype]
1011 prereq_latex = checkForClassExtension(classname)
1013 prereq_list = optAll[1:-1].split(',')
1014 prereq_list = map(checkForClassExtension, prereq_list)
1015 prereq_latex = ','.join(prereq_list)
1016 prereq_docbook = {'true':'', 'false':'docbook'}[bool_docbook]
1017 prereq = {'LaTeX':prereq_latex, 'DocBook':prereq_docbook}[classtype]
1018 return '"%s" "%s" "%s" "%s" "%s"\n' % (classname, opt, desc, avai, prereq)
1019 logger.warning("Layout file " + file + " has no \DeclareXXClass line. ")
1023 def checkLatexConfig(check_config, bool_docbook):
1024 ''' Explore the LaTeX configuration
1025 Return None (will be passed to sys.exit()) for success.
1027 msg = 'checking LaTeX configuration... '
1028 # if --without-latex-config is forced, or if there is no previous
1029 # version of textclass.lst, re-generate a default file.
1030 if not os.path.isfile('textclass.lst') or not check_config:
1031 # remove the files only if we want to regenerate
1032 removeFiles(['textclass.lst', 'packages.lst'])
1034 # Then, generate a default textclass.lst. In case configure.py
1035 # fails, we still have something to start lyx.
1036 logger.info(msg + ' default values')
1037 logger.info('+checking list of textclasses... ')
1038 tx = open('textclass.lst', 'w')
1040 # This file declares layouts and their associated definition files
1041 # (include dir. relative to the place where this file is).
1042 # It contains only default values, since chkconfig.ltx could not be run
1043 # for some reason. Run ./configure.py if you need to update it after a
1044 # configuration change.
1046 # build the list of available layout files and convert it to commands
1049 for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
1050 glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
1052 if not os.path.isfile(file):
1054 # get stuff between /xxxx.layout .
1055 classname = file.split(os.sep)[-1].split('.')[0]
1057 cleanclass = classname.replace(' ', '_')
1058 cleanclass = cleanclass.replace('-', '_')
1059 # make sure the same class is not considered twice
1060 if foundClasses.count(cleanclass) == 0: # not found before
1061 foundClasses.append(cleanclass)
1062 retval = processLayoutFile(file, bool_docbook)
1066 logger.info('\tdone')
1067 if not check_config:
1069 # the following will generate textclass.lst.tmp, and packages.lst.tmp
1070 logger.info(msg + '\tauto')
1071 removeFiles(['chkconfig.classes', 'chkconfig.vars', 'chklayouts.tex',
1072 'wrap_chkconfig.ltx'])
1074 if not os.path.isfile( 'chkconfig.ltx' ):
1075 shutil.copyfile( os.path.join(srcdir, 'chkconfig.ltx'), 'chkconfig.ltx' )
1077 writeToFile('wrap_chkconfig.ltx', '%s\n\\input{chkconfig.ltx}\n' % docbook_cmd)
1078 # Construct the list of classes to test for.
1079 # build the list of available layout files and convert it to commands
1081 declare = re.compile(r'\Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}')
1082 empty = re.compile(r'^\s*$')
1083 testclasses = list()
1084 for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
1085 glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
1086 nodeclaration = False
1087 if not os.path.isfile(file):
1089 classname = file.split(os.sep)[-1].split('.')[0]
1090 for line in open(file).readlines():
1091 if not empty.match(line) and line[0] != '#':
1092 logger.warning("Failed to find valid \Declare line for layout file `" + file + "'.\n\t=> Skipping this file!")
1093 nodeclaration = True
1095 if declare.search(line) == None:
1097 testclasses.append("\\TestDocClass{%s}{%s}" % (classname, line[1:].strip()))
1102 cl = open('chklayouts.tex', 'w')
1103 for line in testclasses:
1104 cl.write(line + '\n')
1107 # we have chklayouts.tex, then process it
1108 fout = os.popen(LATEX + ' wrap_chkconfig.ltx')
1110 line = fout.readline()
1113 if re.match('^\+', line):
1114 logger.info(line.strip())
1115 # if the command succeeds, None will be returned
1118 # currently, values in chhkconfig are only used to set
1121 for line in open('chkconfig.vars').readlines():
1122 key, val = re.sub('-', '_', line).split('=')
1124 values[key] = val.strip("'")
1125 # chk_fontenc may not exist
1127 addToRC(r'\font_encoding "%s"' % values["chk_fontenc"])
1130 if rmcopy: # remove the copied file
1131 removeFiles( [ 'chkconfig.ltx' ] )
1132 # if configure successed, move textclass.lst.tmp to textclass.lst
1133 # and packages.lst.tmp to packages.lst
1134 if os.path.isfile('textclass.lst.tmp') and len(open('textclass.lst.tmp').read()) > 0 \
1135 and os.path.isfile('packages.lst.tmp') and len(open('packages.lst.tmp').read()) > 0:
1136 shutil.move('textclass.lst.tmp', 'textclass.lst')
1137 shutil.move('packages.lst.tmp', 'packages.lst')
1141 def checkModulesConfig():
1142 removeFiles(['lyxmodules.lst', 'chkmodules.tex'])
1144 logger.info('+checking list of modules... ')
1145 tx = open('lyxmodules.lst', 'w')
1146 tx.write('''## This file declares modules and their associated definition files.
1147 ## It has been automatically generated by configure
1148 ## Use "Options/Reconfigure" if you need to update it after a
1149 ## configuration change.
1150 ## "ModuleName" "filename" "Description" "Packages" "Requires" "Excludes" "Category"
1153 # build the list of available modules
1155 # note that this searches the local directory first, then the
1156 # system directory. that way, we pick up the user's version first.
1157 for file in glob.glob( os.path.join('layouts', '*.module') ) + \
1158 glob.glob( os.path.join(srcdir, 'layouts', '*.module' ) ) :
1161 if not os.path.isfile(file):
1164 filename = file.split(os.sep)[-1]
1165 filename = filename[:-7]
1166 if seen.count(filename):
1169 seen.append(filename)
1170 retval = processModuleFile(file, filename, bool_docbook)
1174 logger.info('\tdone')
1177 def processModuleFile(file, filename, bool_docbook):
1178 ''' process module file and get a line of result
1180 The top of a module file should look like this:
1181 #\DeclareLyXModule[LaTeX Packages]{ModuleName}
1183 #...body of description...
1185 #Requires: [list of required modules]
1186 #Excludes: [list of excluded modules]
1187 #Category: [category name]
1188 The last three lines are optional (though do give a category).
1190 "ModuleName" "filename" "Description" "Packages" "Requires" "Excludes" "Category"
1192 remods = re.compile(r'\DeclareLyXModule\s*(?:\[([^]]*?)\])?{(.*)}')
1193 rereqs = re.compile(r'#+\s*Requires: (.*)')
1194 reexcs = re.compile(r'#+\s*Excludes: (.*)')
1195 recaty = re.compile(r'#+\s*Category: (.*)')
1196 redbeg = re.compile(r'#+\s*DescriptionBegin\s*$')
1197 redend = re.compile(r'#+\s*DescriptionEnd\s*$')
1199 modname = desc = pkgs = req = excl = catgy = ""
1200 readingDescription = False
1203 for line in open(file).readlines():
1204 if readingDescription:
1205 res = redend.search(line)
1207 readingDescription = False
1208 desc = " ".join(descLines)
1210 desc = desc.replace('"', '\\"')
1212 descLines.append(line[1:].strip())
1214 res = redbeg.search(line)
1216 readingDescription = True
1218 res = remods.search(line)
1220 (pkgs, modname) = res.groups()
1224 tmp = [s.strip() for s in pkgs.split(",")]
1225 pkgs = ",".join(tmp)
1227 res = rereqs.search(line)
1230 tmp = [s.strip() for s in req.split("|")]
1233 res = reexcs.search(line)
1236 tmp = [s.strip() for s in excl.split("|")]
1237 excl = "|".join(tmp)
1239 res = recaty.search(line)
1241 catgy = res.group(1)
1245 logger.warning("Module file without \DeclareLyXModule line. ")
1249 # this module has some latex dependencies:
1250 # append the dependencies to chkmodules.tex,
1251 # which is \input'ed by chkconfig.ltx
1252 testpackages = list()
1253 for pkg in pkgs.split(","):
1255 # this is a converter dependency: skip
1257 if pkg.endswith(".sty"):
1259 testpackages.append("\\TestPackage{%s}" % (pkg,))
1260 cm = open('chkmodules.tex', 'a')
1261 for line in testpackages:
1262 cm.write(line + '\n')
1265 return '"%s" "%s" "%s" "%s" "%s" "%s" "%s"\n' % (modname, filename, desc, pkgs, req, excl, catgy)
1268 def checkTeXAllowSpaces():
1269 ''' Let's check whether spaces are allowed in TeX file names '''
1270 tex_allows_spaces = 'false'
1271 if lyx_check_config:
1272 msg = "Checking whether TeX allows spaces in file names... "
1273 writeToFile('a b.tex', r'\message{working^^J}' )
1275 if os.name == 'nt' or sys.platform == 'cygwin':
1276 latex_out = cmdOutput(LATEX + r""" "\nonstopmode\input{\"a b\"}" """)
1278 latex_out = cmdOutput(LATEX + r""" '\nonstopmode\input{"a b"}' """)
1281 if 'working' in latex_out:
1282 logger.info(msg + 'yes')
1283 tex_allows_spaces = 'true'
1285 logger.info(msg + 'no')
1286 tex_allows_spaces = 'false'
1287 addToRC(r'\tex_allows_spaces ' + tex_allows_spaces)
1288 removeFiles( [ 'a b.tex', 'a b.log', 'texput.log' ])
1291 def removeTempFiles():
1293 if not lyx_keep_temps:
1294 removeFiles(['chkconfig.vars', 'chklatex.ltx', 'chklatex.log',
1295 'chklayouts.tex', 'chkmodules.tex', 'missfont.log',
1296 'wrap_chkconfig.ltx', 'wrap_chkconfig.log'])
1299 if __name__ == '__main__':
1300 lyx_check_config = True
1301 outfile = 'lyxrc.defaults'
1302 lyxrc_fileformat = 1
1304 lyx_keep_temps = False
1306 ## Parse the command line
1307 for op in sys.argv[1:]: # default shell/for list is $*, the options
1308 if op in [ '-help', '--help', '-h' ]:
1309 print '''Usage: configure [options]
1311 --help show this help lines
1312 --keep-temps keep temporary files (for debug. purposes)
1313 --without-latex-config do not run LaTeX to determine configuration
1314 --with-version-suffix=suffix suffix of binary installed files
1317 elif op == '--without-latex-config':
1318 lyx_check_config = False
1319 elif op == '--keep-temps':
1320 lyx_keep_temps = True
1321 elif op[0:22] == '--with-version-suffix=': # never mind if op is not long enough
1322 version_suffix = op[22:]
1324 print "Unknown option", op
1327 # check if we run from the right directory
1328 srcdir = os.path.dirname(sys.argv[0])
1331 if not os.path.isfile( os.path.join(srcdir, 'chkconfig.ltx') ):
1332 logger.error("configure: error: cannot find chkconfig.ltx script")
1336 dtl_tools = checkDTLtools()
1337 ## Write the first part of outfile
1338 writeToFile(outfile, '''# This file has been automatically generated by LyX' lib/configure.py
1339 # script. It contains default settings that have been determined by
1340 # examining your system. PLEASE DO NOT MODIFY ANYTHING HERE! If you
1341 # want to customize LyX, use LyX' Preferences dialog or modify directly
1342 # the "preferences" file instead. Any setting in that file will
1343 # override the values given here.
1347 ''' % lyxrc_fileformat)
1349 LATEX = checkLatex(dtl_tools)
1350 checkFormatEntries(dtl_tools)
1351 checkConverterEntries()
1352 (chk_docbook, bool_docbook, docbook_cmd) = checkDocBook()
1353 checkTeXAllowSpaces()
1354 windows_style_tex_paths = checkTeXPaths()
1355 if windows_style_tex_paths != '':
1356 addToRC(r'\tex_expects_windows_paths %s' % windows_style_tex_paths)
1358 checkModulesConfig()
1359 # --without-latex-config can disable lyx_check_config
1360 ret = checkLatexConfig(lyx_check_config and LATEX != '', bool_docbook)
1362 # The return error code can be 256. Because most systems expect an error code
1363 # in the range 0-127, 256 can be interpretted as 'success'. Because we expect
1364 # a None for success, 'ret is not None' is used to exit.
1365 sys.exit(ret is not None)