16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 */ |
17 */ |
18 package cz.frantovo.xmlWebGenerator; |
18 package cz.frantovo.xmlWebGenerator; |
19 |
19 |
20 import java.io.File; |
20 import java.io.File; |
21 import java.io.IOException; |
|
22 import java.io.PrintStream; |
|
23 import java.util.Date; |
21 import java.util.Date; |
24 import java.net.URI; |
22 import java.net.URI; |
25 import java.net.URISyntaxException; |
23 import java.net.URISyntaxException; |
26 import java.net.URLDecoder; |
|
27 import java.nio.charset.Charset; |
|
28 import static cz.frantovo.xmlWebGenerator.NástrojeCLI.*; |
|
29 |
24 |
30 /** |
25 /** |
31 * Knihovna funkcí volaných z XSLT. |
26 * Společná knihovna funkcí volaných z XSLT |
32 * |
27 * |
33 * TODO: |
28 * @author František Kučera (frantovo.cz) |
34 * - rozdělit na více modulů (jmenných prostorů). |
|
35 * - CLI konektor |
|
36 * |
|
37 * @author fiki |
|
38 */ |
29 */ |
39 public class Funkce { |
30 public class Funkce { |
40 |
31 |
41 private static final String PŘÍKAZ_PYGMENTIZE = "pygmentize"; |
|
42 private static final String PŘÍKAZ_DOT = "dot"; |
|
43 private static final String PŘÍKAZ_MARKDOWN = "markdown"; |
|
44 private static final String ADRESÁŘ_VÝSTUPNÍ = "výstup"; |
|
45 private static int počítadloDiagramů = 0; |
|
46 private static String počítadloDiagramůKontext = ""; // aktuálně zpracovávaná stránka, při změně vynulujeme počítadlo |
|
47 |
|
48 /** |
32 /** |
49 * Zjištuje, kdy byl naposledy daný soubor změněn. |
33 * Zjištuje, kdy byl naposledy daný soubor změněn. |
50 * @param soubor cesta k souboru |
34 * @param soubor cesta k souboru |
51 * @return datum poslední změny |
35 * @return datum poslední změny |
52 * @throws URISyntaxException |
36 * @throws URISyntaxException |
54 public static Date posledníZměna(String soubor) throws URISyntaxException { |
38 public static Date posledníZměna(String soubor) throws URISyntaxException { |
55 URI uri = new URI(soubor); |
39 URI uri = new URI(soubor); |
56 File f = new File(uri); |
40 File f = new File(uri); |
57 return new Date(f.lastModified()); |
41 return new Date(f.lastModified()); |
58 } |
42 } |
59 |
|
60 /** |
|
61 * Zvýrazňuje syntaxi zdrojového kódu. Používá k tomu externí program/knihovnu pygmentize. |
|
62 * @param zdroják zdrojový kód, který předáme příkazu pygmentize na standardním vstupu |
|
63 * @param jazyk předáme příkazu pygmentize jako parametr -l <lexer> |
|
64 * @return zvýrazněný text nebo null, pokud došlo k chybě. |
|
65 * TODO: |
|
66 * - vracet místo textu instanci com.icl.saxon.om.NodeInfo http://saxon.sourceforge.net/saxon6.5.3/extensibility.html |
|
67 * - nebo kontrolovat validitu vygenerovaného kódu (v současnosti se spoléháme na bezchybnost pygmentize) |
|
68 */ |
|
69 public static String zvýrazniSyntaxi(String zdroják, String jazyk) throws IOException, InterruptedException { |
|
70 if (jazyk == null || jazyk.length() == 0) { |
|
71 System.err.println("Není vyplněn atribut „jazyk“ → není jasné, jak se má zvýrazňovat."); |
|
72 return null; |
|
73 } else if (isPříkazDostupný(PŘÍKAZ_PYGMENTIZE)) { |
|
74 Runtime r = Runtime.getRuntime(); |
|
75 Process p = r.exec(new String[]{PŘÍKAZ_PYGMENTIZE, "-f", "html", "-l", jazyk}); |
|
76 |
|
77 PrintStream vstupProcesu = new PrintStream(p.getOutputStream()); |
|
78 vstupProcesu.print(zdroják); |
|
79 vstupProcesu.close(); |
|
80 |
|
81 String výsledek = načtiProud(p.getInputStream()); |
|
82 String chyby = načtiProud(p.getErrorStream()); |
|
83 |
|
84 p.waitFor(); |
|
85 |
|
86 if (chyby.length() == 0) { |
|
87 // Pozor: pygmentize má i při chybě návratový kód 0 → je potřeba kontrolovat chybový výstup. |
|
88 return výsledek; |
|
89 } else { |
|
90 System.err.print("Při zvýrazňování syntaxe došlo k chybě: " + chyby); |
|
91 return null; |
|
92 } |
|
93 } else { |
|
94 System.err.println("Příkaz " + PŘÍKAZ_PYGMENTIZE + " není na vašem systému dostupný → zvýrazňování syntaxe nebude fungovat."); |
|
95 System.err.println("Můžete ho nainstalovat pomocí:"); |
|
96 System.err.println("\t$ aptitude install python-pygments # (Debian/Ubuntu)"); |
|
97 System.err.println("\t$ yum install python-pygments # (Fedora/RedHat)"); |
|
98 return null; |
|
99 } |
|
100 } |
|
101 |
|
102 /** |
|
103 * Vygeneruje CSS styl pro zvýrazňování syntaxe. |
|
104 * @return obsah CSS souboru nebo null, pokud generování nebylo možné |
|
105 */ |
|
106 public static String generujCssSyntaxe() throws IOException, InterruptedException { |
|
107 if (isPříkazDostupný(PŘÍKAZ_PYGMENTIZE)) { |
|
108 Runtime r = Runtime.getRuntime(); |
|
109 Process p = r.exec(new String[]{PŘÍKAZ_PYGMENTIZE, "-S", "default", "-f", "html"}); |
|
110 return načtiProud(p.getInputStream()); |
|
111 } else { |
|
112 return null; |
|
113 } |
|
114 } |
|
115 |
|
116 /** |
|
117 * Vytvoří obrázek s diagramem. |
|
118 * @param zadání definice diagramu ve formátu dot |
|
119 * @param vodorovně zda má být graf orientovaný vodorovně (funguje jen při <code>kompletní = false</code>) |
|
120 * @param kompletní false, pokud k zadání chceme doplnit <code>digraph d {…}</code> |
|
121 * @param kontext kam diagram patří – typicky název stránky, do které je vložen |
|
122 * diagramy se pak budou číslovat v rámci tohoto kontextu |
|
123 * → nebude docházet k přepisování diagramů jiných stránek při částečném přegenerování webu. |
|
124 * @param souborZadání null pokud chceme automatické číslování | nebo zadáme název souboru se zadáním diagramu – vygenerovaný diagram se pak bude jmenovat stejně |
|
125 * @return název souboru bez přípony, který byl vytvořen, nebo null, pokud došlo k chybě. |
|
126 */ |
|
127 public static String vytvořDiagram(String zadání, boolean vodorovně, boolean kompletní, String kontext, String souborZadání) throws IOException, InterruptedException { |
|
128 if (isPříkazDostupný(PŘÍKAZ_DOT)) { |
|
129 |
|
130 String soubor; |
|
131 if (souborZadání == null) { |
|
132 if (kontext == null) { |
|
133 počítadloDiagramů++; |
|
134 soubor = "diagram-" + počítadloDiagramů; |
|
135 } else { |
|
136 // TODO: tohle by se mělo udělat v XSLT |
|
137 kontext = URLDecoder.decode(kontext, Charset.defaultCharset().name()); |
|
138 |
|
139 // Každá stránka bude mít svoje diagramy číslované od 1 |
|
140 if (!počítadloDiagramůKontext.equals(kontext)) { |
|
141 počítadloDiagramůKontext = kontext; |
|
142 počítadloDiagramů = 0; |
|
143 } |
|
144 |
|
145 počítadloDiagramů++; |
|
146 soubor = "diagram-" + kontext + "-" + počítadloDiagramů; |
|
147 } |
|
148 } else { |
|
149 soubor = souborZadání; |
|
150 } |
|
151 String souborSložka = ADRESÁŘ_VÝSTUPNÍ + File.separator + soubor; |
|
152 |
|
153 String zdroják; |
|
154 if (kompletní) { |
|
155 zdroják = zadání; |
|
156 } else { |
|
157 StringBuilder b = new StringBuilder(zadání.length() + 200); |
|
158 b.append("digraph d {\n"); |
|
159 b.append("\tbgcolor=\"transparent\";\n"); |
|
160 if (vodorovně) { |
|
161 b.append("\trankdir=LR;"); |
|
162 } |
|
163 b.append(zadání); |
|
164 b.append("}\n"); |
|
165 zdroják = b.toString(); |
|
166 } |
|
167 |
|
168 Runtime r = Runtime.getRuntime(); |
|
169 Process p = r.exec(new String[]{PŘÍKAZ_DOT, "-T", "svg", "-o", souborSložka + ".svg"}); |
|
170 |
|
171 /** |
|
172 * TODO: generovat i PNG bitmapu |
|
173 */ |
|
174 PrintStream vstupProcesu = new PrintStream(p.getOutputStream()); |
|
175 vstupProcesu.print(zdroják.toString()); |
|
176 vstupProcesu.close(); |
|
177 |
|
178 String chyby = načtiProud(p.getErrorStream()); |
|
179 |
|
180 p.waitFor(); |
|
181 |
|
182 if (chyby.length() == 0) { |
|
183 return soubor; |
|
184 } else { |
|
185 System.err.print("Při vytváření diagramu došlo k chybě: " + chyby); |
|
186 return null; |
|
187 } |
|
188 } else { |
|
189 System.err.println("Příkaz " + PŘÍKAZ_DOT + " není na vašem systému dostupný → diagramy nelze vygreslit."); |
|
190 System.err.println("Můžete ho nainstalovat pomocí:"); |
|
191 System.err.println("\t$ aptitude install graphviz # (Debian/Ubuntu)"); |
|
192 System.err.println("\t$ yum install graphviz # (Fedora/RedHat)"); |
|
193 return null; |
|
194 } |
|
195 } |
|
196 |
|
197 /** |
|
198 * Převede text ve wiki syntaxi do XHTML. |
|
199 * @param wiki vstupní text v dané wiki syntaxi |
|
200 * @param syntaxe null nebo volitelně syntaxe (markdown, texy) |
|
201 * @return naformátované XHTML |
|
202 */ |
|
203 public static String formátujWiki(String wiki, String syntaxe) throws IOException { |
|
204 if (isPříkazDostupný(PŘÍKAZ_MARKDOWN)) { |
|
205 Runtime r = Runtime.getRuntime(); |
|
206 Process p = r.exec(new String[]{PŘÍKAZ_MARKDOWN}); |
|
207 |
|
208 /** |
|
209 * TODO: oříznout mezery na začátcích řádků, pokud je jich všude stejně? |
|
210 * (odsazení v XML) |
|
211 */ |
|
212 PrintStream vstupProcesu = new PrintStream(p.getOutputStream()); |
|
213 vstupProcesu.print(wiki); |
|
214 vstupProcesu.close(); |
|
215 |
|
216 String chyby = načtiProud(p.getErrorStream()); |
|
217 String xhtml = načtiProud(p.getInputStream()); |
|
218 |
|
219 if (chyby.length() == 0) { |
|
220 return xhtml; |
|
221 } else { |
|
222 System.err.print("Při zpracování wiki syntaxe došlo k chybě: " + chyby); |
|
223 return null; |
|
224 } |
|
225 } else { |
|
226 System.err.println("Příkaz " + PŘÍKAZ_MARKDOWN + " není na vašem systému dostupný → nelze formátovat texty ve wiki syntaxi."); |
|
227 System.err.println("Můžete ho nainstalovat pomocí:"); |
|
228 System.err.println("\t$ aptitude install markdown # (Debian/Ubuntu)"); |
|
229 System.err.println("\t$ yum install perl-Text-Markdown # (Fedora/RedHat)"); |
|
230 return null; |
|
231 } |
|
232 } |
|
233 } |
43 } |