šablona/funkce/src/cz/frantovo/xmlWebGenerator/Funkce.java
author František Kučera <franta-hg@frantovo.cz>
Tue, 13 Sep 2011 18:06:07 +0200
changeset 37 2e4e7891a2f7
parent 36 5be21d1ef5f8
child 38 43505795334d
permissions -rw-r--r--
Wiki syntaxe #7 – základ, podpora Markdown syntaxe.
     1 package cz.frantovo.xmlWebGenerator;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.File;
     5 import java.io.IOException;
     6 import java.io.InputStream;
     7 import java.io.InputStreamReader;
     8 import java.io.PrintStream;
     9 import java.util.Date;
    10 import java.net.URI;
    11 import java.net.URISyntaxException;
    12 
    13 /**
    14  * Knihovna funkcí volaných z XSLT.
    15  *  
    16  * TODO:
    17  *	- rozdělit na více modulů (jmenných prostorů).
    18  *	- CLI konektor
    19  * 
    20  * @author fiki
    21  */
    22 public class Funkce {
    23 
    24 	private static final String PŘÍKAZ_PYGMENTIZE = "pygmentize";
    25 	private static final String PŘÍKAZ_DOT = "dot";
    26 	private static final String PŘÍKAZ_MARKDOWN = "markdown";
    27 	private static final String PŘÍKAZ_WHICH = "which";
    28 	private static final String ADRESÁŘ_VÝSTUPNÍ = "výstup";
    29 	private static int počítadloDiagramů = 0;
    30 
    31 	/**
    32 	 * Zjištuje, kdy byl naposledy daný soubor změněn.
    33 	 * @param soubor cesta k souboru
    34 	 * @return datum poslední změny
    35 	 * @throws URISyntaxException
    36 	 */
    37 	public static Date posledníZměna(String soubor) throws URISyntaxException {
    38 		URI uri = new URI(soubor);
    39 		File f = new File(uri);
    40 		return new Date(f.lastModified());
    41 	}
    42 
    43 	/**
    44 	 * Zvýrazňuje syntaxi zdrojového kódu. Používá k tomu externí program/knihovnu pygmentize.
    45 	 * @param zdroják zdrojový kód, který předáme příkazu pygmentize na standardním vstupu
    46 	 * @param jazyk předáme příkazu pygmentize jako parametr -l &lt;lexer&gt;
    47 	 * @return zvýrazněný text nebo null, pokud došlo k chybě.
    48 	 * TODO: 
    49 	 *	- vracet místo textu instanci com.icl.saxon.om.NodeInfo http://saxon.sourceforge.net/saxon6.5.3/extensibility.html
    50 	 *  - nebo kontrolovat validitu vygenerovaného kódu (v současnosti se spoléháme na bezchybnost pygmentize)
    51 	 */
    52 	public static String zvýrazniSyntaxi(String zdroják, String jazyk) throws IOException, InterruptedException {
    53 		if (jazyk == null || jazyk.length() == 0) {
    54 			System.err.println("Není vyplněn atribut „jazyk“ → není jasné, jak se má zvýrazňovat.");
    55 			return null;
    56 		} else if (isPříkazDostupný(PŘÍKAZ_PYGMENTIZE)) {
    57 			Runtime r = Runtime.getRuntime();
    58 			Process p = r.exec(new String[]{PŘÍKAZ_PYGMENTIZE, "-f", "html", "-l", jazyk});
    59 
    60 			PrintStream vstupProcesu = new PrintStream(p.getOutputStream());
    61 			vstupProcesu.print(zdroják);
    62 			vstupProcesu.close();
    63 
    64 			String výsledek = načtiProud(p.getInputStream());
    65 			String chyby = načtiProud(p.getErrorStream());
    66 
    67 			p.waitFor();
    68 
    69 			if (chyby.length() == 0) {
    70 				// Pozor: pygmentize má i při chybě návratový kód 0 → je potřeba kontrolovat chybový výstup.
    71 				return výsledek;
    72 			} else {
    73 				System.err.print("Při zvýrazňování syntaxe došlo k chybě: " + chyby);
    74 				return null;
    75 			}
    76 		} else {
    77 			System.err.println("Příkaz " + PŘÍKAZ_PYGMENTIZE + " není na vašem systému dostupný → zvýrazňování syntaxe nebude fungovat.");
    78 			System.err.println("Můžete ho nainstalovat pomocí:");
    79 			System.err.println("\t$ aptitude install python-pygments   # (Debian/Ubuntu)");
    80 			System.err.println("\t$ yum install python-pygments        # (Fedora/RedHat)");
    81 			return null;
    82 		}
    83 	}
    84 
    85 	/**
    86 	 * Vygeneruje CSS styl pro zvýrazňování syntaxe.
    87 	 * @return obsah CSS souboru nebo null, pokud generování nebylo možné
    88 	 */
    89 	public static String generujCssSyntaxe() throws IOException, InterruptedException {
    90 		if (isPříkazDostupný(PŘÍKAZ_PYGMENTIZE)) {
    91 			Runtime r = Runtime.getRuntime();
    92 			Process p = r.exec(new String[]{PŘÍKAZ_PYGMENTIZE, "-S", "default", "-f", "html"});
    93 			return načtiProud(p.getInputStream());
    94 		} else {
    95 			return null;
    96 		}
    97 	}
    98 
    99 	/**
   100 	 * Vytvoří obrázek s diagramem.
   101 	 * @param zadání definice diagramu ve formátu dot
   102 	 * @param vodorovně zda má být graf orientovaný vodorovně
   103 	 * @return název souboru bez přípony, který byl vytvořen, nebo null, pokud došlo k chybě.
   104 	 */
   105 	public static String vytvořDiagram(String zadání, boolean vodorovně) throws IOException, InterruptedException {
   106 		if (isPříkazDostupný(PŘÍKAZ_DOT)) {
   107 			počítadloDiagramů++;
   108 			String soubor = "diagram-" + počítadloDiagramů;
   109 			String souborSložka = ADRESÁŘ_VÝSTUPNÍ + File.separator + soubor;
   110 
   111 			StringBuilder zdroják = new StringBuilder(zadání.length() + 200);
   112 
   113 			zdroják.append("digraph d {\n");
   114 			zdroják.append("\tbgcolor=\"transparent\";\n");
   115 			if (vodorovně) {
   116 				zdroják.append("\trankdir=LR;");
   117 			}
   118 			zdroják.append(zadání);
   119 			zdroják.append("}\n");
   120 
   121 			Runtime r = Runtime.getRuntime();
   122 			Process p = r.exec(new String[]{PŘÍKAZ_DOT, "-T", "svg", "-o", souborSložka + ".svg"});
   123 
   124 			/**
   125 			 * TODO: generovat i PNG bitmapu
   126 			 */
   127 			PrintStream vstupProcesu = new PrintStream(p.getOutputStream());
   128 			vstupProcesu.print(zdroják.toString());
   129 			vstupProcesu.close();
   130 
   131 			String chyby = načtiProud(p.getErrorStream());
   132 
   133 			p.waitFor();
   134 
   135 			if (chyby.length() == 0) {
   136 				return soubor;
   137 			} else {
   138 				System.err.print("Při vytváření diagramu došlo k chybě: " + chyby);
   139 				return null;
   140 			}
   141 		} else {
   142 			System.err.println("Příkaz " + PŘÍKAZ_DOT + " není na vašem systému dostupný → diagramy nelze vygreslit.");
   143 			System.err.println("Můžete ho nainstalovat pomocí:");
   144 			System.err.println("\t$ aptitude install graphviz   # (Debian/Ubuntu)");
   145 			System.err.println("\t$ yum install graphviz        # (Fedora/RedHat)");
   146 			return null;
   147 		}
   148 	}
   149 
   150 	/**
   151 	 * Převede text ve wiki syntaxi do XHTML.
   152 	 * @param wiki vstupní text v dané wiki syntaxi
   153 	 * @param syntaxe null nebo volitelně syntaxe (markdown, texy)
   154 	 * @return naformátované XHTML
   155 	 */
   156 	public static String formátujWiki(String wiki, String syntaxe) throws IOException {
   157 		if (isPříkazDostupný(PŘÍKAZ_MARKDOWN)) {
   158 			Runtime r = Runtime.getRuntime();
   159 			Process p = r.exec(new String[]{PŘÍKAZ_MARKDOWN});
   160 
   161 			/**
   162 			 * TODO: oříznout mezery na začátcích řádků, pokud je jich všude stejně?
   163 			 * (odsazení v XML)
   164 			 */
   165 			PrintStream vstupProcesu = new PrintStream(p.getOutputStream());
   166 			vstupProcesu.print(wiki);
   167 			vstupProcesu.close();
   168 
   169 			String chyby = načtiProud(p.getErrorStream());
   170 			String xhtml = načtiProud(p.getInputStream());
   171 
   172 			if (chyby.length() == 0) {
   173 				return xhtml;
   174 			} else {
   175 				System.err.print("Při zpracování wiki syntaxe došlo k chybě: " + chyby);
   176 				return null;
   177 			}
   178 		} else {
   179 			System.err.println("Příkaz " + PŘÍKAZ_MARKDOWN + " není na vašem systému dostupný → nelze formátovat texty ve wiki syntaxi.");
   180 			System.err.println("Můžete ho nainstalovat pomocí:");
   181 			System.err.println("\t$ aptitude install markdown         # (Debian/Ubuntu)");
   182 			System.err.println("\t$ yum install perl-Text-Markdown    # (Fedora/RedHat)");
   183 			return null;
   184 		}
   185 	}
   186 
   187 	/**
   188 	 * Čte proud dat dokud to jde a výsledek pak vrátí jako text.
   189 	 * @param proud vstupní proud
   190 	 * @return obsah proudu jako text
   191 	 * @throws IOException 
   192 	 */
   193 	private static String načtiProud(InputStream proud) throws IOException {
   194 		StringBuilder výsledek = new StringBuilder();
   195 		BufferedReader buf = new BufferedReader(new InputStreamReader(proud));
   196 		while (true) {
   197 			String radek = buf.readLine();
   198 			if (radek == null) {
   199 				break;
   200 			} else {
   201 				výsledek.append(radek);
   202 				výsledek.append("\n");
   203 			}
   204 		}
   205 		return výsledek.toString();
   206 	}
   207 
   208 	/**
   209 	 * Pomocí programu which zjistí, jestli je daný příkaz v systému přítomný.
   210 	 * @param příkaz jehož přítomnost zjišťujeme
   211 	 * @return true pokud příkaz v systému existuje
   212 	 */
   213 	private static boolean isPříkazDostupný(String příkaz) {
   214 		try {
   215 			Runtime r = Runtime.getRuntime();
   216 			Process p = r.exec(new String[]{PŘÍKAZ_WHICH, příkaz});
   217 			p.waitFor();
   218 			return p.exitValue() == 0;
   219 		} catch (Exception e) {
   220 			System.err.printf("Při zjišťování dostupnosti příkazu „%s“ došlo k chybě: %s", příkaz, e.getLocalizedMessage());
   221 			return false;
   222 		}
   223 	}
   224 }