
com.sta.cts.CheckStyleRunner Maven / Gradle / Ivy
package com.sta.cts;
import java.util.ArrayList;
import java.util.List;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import com.sta.mlogger.MLogEntry;
import com.sta.mlogger.MLogEntry4Text;
import com.sta.mlogger.MLogger;
import com.sta.mutils.FileUtils;
/**
* Name: CheckStyleRunner
* Description: Hilfsklasse, um die Dokumenterzeugung f?r Checkstyle von Maven aus aufzurufen.
* Dabei werden die n?tigen Stylesheets und Ressourcen ins Zielverzeichnis kopiert.
* Es wird davon ausgegangen, dass CheckStyle selbst von Maven aus direkt ausgef?hrt wird und die CheckStyle-Ergebnisdatei
* vorliegt.
*
* Comment: Die Variante, CheckStyle selbst ebenfalls vom CheckStyleRunner ausf?hren zu lassen, wurde verworfen.
* Es soll das Maven-CheckStyle-Plugin verwendet werden. Hintergrund ist, dass die Zieldatei ben?tigt wird, um in der Ansicht
* auf dem Build-Server einen CheckStyle-Trend darzustellen. Hierzu sollte vom Standard-Dateinamen und der Standard-Position
* der Datei ausgegangen werden.
*
* Copyright: Copyright (c) 2018-2021
* Company: >StA-Soft<
* @author StA
* @version 1.0
*/
public class CheckStyleRunner
{
/**
* CheckStyle-Ressourcen-Verzeichnis.
*/
private static final String CHECKSTYLE_RESOURCE_DIR = "checkstyle/";
/**
* F?r CheckStyle notwendige Dateien.
*/
private static final String[] CHECKSTYLE_FILES = new String[] { "sailboat_sta.png", "sailboat_simple.png", "checkstyle_frm.xsl", "report_frm.xsl", "report_frm_htm.xsl", "report_frm_fo.xsl" };
//===========================================================================
/**
* Maske mit Wildcards in einen regul?ren Ausdruck umwandeln.
* @param mask Maske
* @return regul?rer Ausdruck
*/
private static String getRegExpr(String mask)
{
StringBuilder sb = new StringBuilder();
int len = mask.length();
for (int i = 0; i < len; i++)
{
char ch = mask.charAt(i);
if (ch == '*')
{
sb.append(".*");
}
else if (ch == '?')
{
sb.append(".");
}
else if (ch == '.')
{
sb.append("[.]");
}
else
{
sb.append(ch);
}
}
return sb.toString();
}
/**
* Alle auf ein Muster passenden Dateinamen ausgehend von einem Basisverzeichnis rekursiv ermitteln.
* @param dir Basisverzeichnis
* @param mask Muster (mit ?*)
* @return Menge der Namen passender Dateien
* @throws IOException im Fehlerfall
*/
private static List getFileNames(File dir, String mask) throws IOException
{
int idx = mask.indexOf("/");
if (idx >= 0)
{
String next = mask.substring(0, idx);
String rest = mask.substring(idx + 1);
if (".".equals(next))
{
return getFileNames(dir, rest);
}
if ("..".equals(next))
{
return getFileNames(new File(dir, ".."), rest);
}
String regex = getRegExpr(next);
File[] files = dir.listFiles(new FilenameFilter()
{
@Override
public boolean accept(File dir, String name)
{
return name.matches(regex);
}
});
ArrayList res = new ArrayList<>();
if (files != null)
{
for (File f : files)
{
List list = getFileNames(f, rest);
res.addAll(list);
}
}
return res;
}
else
{
String regex = getRegExpr(mask);
File[] files = dir.listFiles(new FilenameFilter()
{
@Override
public boolean accept(File dir, String name)
{
return name.matches(regex);
}
});
ArrayList res = new ArrayList<>();
for (File f : files)
{
res.add(f.getCanonicalPath()); // kompletter Pfad, "."/".." aufl?sen
}
return res;
}
}
/**
* Attribute eines XML-Tags kopieren.
* @param xg XML-Generator
* @param tag XML-Tag
*/
private static void copyAttrs(XMLGenerator xg, XMLTag tag)
{
tag.getAttributes().forEach((key, value) ->
{
try
{
xg.putAttr(key, value);
}
catch (IOException ex)
{
MLogger.wrn("Can't write attribute: " + key + " = " + value);
}
});
}
/**
* Inhalt einer XML-Datei zwischen bestimmten Tags (?u?erste Ebene dieser Tag) in eine Ziel-XML-Datei ?bertragen, ohne ein
* separates Root-Tag zu schreiben.
* @param xg XML-Generator
* @param fn XML-Quelldatei
* @param tagname Tag-Name
* @throws IOException im Fehlerfall
*/
private static void addXML(XMLGenerator xg, String fn, String tagname) throws IOException
{
XMLScanner xs = new XMLScanner();
xs.init(fn);
try
{
xs.initH(null);
// alles lesen
// falls Tag tagname ?ffnend kommt: counter hochz?hlen
// falls Tag tagname schlie?end kommt: counter runterz?hlen
// falls ein anderes Tag kommt und counter > 0: in Zieldatei schreiben, incl. der Attribute
// falls Inhalt kommt und counter > 0: in die Zieldatei schreiben
int counter = 0;
Object obj;
while ((obj = xs.getToken()) != null)
{
if (obj instanceof XMLTag)
{
XMLTag tag = (XMLTag) obj;
if (tagname.equals(tag.getName()))
{
if (tag.isOpen())
{
if (counter > 0)
{
xg.openTag(tag.getName());
copyAttrs(xg, tag);
}
counter++;
}
if (tag.isClose())
{
counter--;
if (counter > 0)
{
xg.closeTag(tag.getName());
}
}
}
else
{
if (counter > 0)
{
if (tag.isOpen())
{
xg.openTag(tag.getName());
copyAttrs(xg, tag);
}
if (tag.isClose())
{
xg.closeTag(tag.getName());
}
}
}
}
else if (obj instanceof String)
{
if (counter > 0)
{
xg.write((String) obj);
}
}
}
}
finally
{
xs.close();
}
}
/**
* Standard-Main-Methode.
* @param args Kommandozeilenargumente
* @throws Exception im Fehlerfall
*/
public static void main(String... args) throws Exception
{
// Index
// 0: Quell-Dateiname (CheckStyle-Ergebnisdatei, target/checkstyle-result.xml)
// 1: Zielverzeichnis (f?r CheckStyle-Report und Ressourcen, target/checkstyle)
// 2: Projektname (steht sp?ter im CheckStyle-Report)
String srcfilename = args[0];
String dstdir = args[1];
String prjname = args[2];
MLogEntry mle = new MLogEntry4Text();
mle.setMLogFormat("%msg");
mle.setBreakAfterOutput(true);
MLogger.addMLogEntryTS(mle);
try
{
// falls srcfilename Wildcards (*?) enth?lt, dann
// * alle passenden Dateien ermitteln
// * Zielverzeichnis anlegen
// * dort eine tempor?re Datei anlegen
// * Quelldateien zusammenkopieren in tempor?re Datei
// * Name der tempor?ren Datei weiter als srcfilename verwenden
boolean aggregate = false;
if (srcfilename.contains("?") || srcfilename.contains("*"))
{
MLogger.inf("mask: " + srcfilename);
List filenames = getFileNames(new File("."), srcfilename);
if (filenames.size() == 0)
{
MLogger.inf("CheckStyle: Nothing found. Exiting.");
return;
}
// erst an dieser Stelle, also nach dem Test, ob Quelldateien existieren
File ddir = new File(dstdir);
ddir.mkdirs();
File tmp = File.createTempFile("checkstyle-aggregate-result-", ".xml", ddir);
XMLGenerator xg = new XMLGenerator();
xg.createXML(tmp.getPath());
try
{
xg.openTag("checkstyle");
for (String fn : filenames)
{
MLogger.inf("found: " + fn);
addXML(xg, fn, "checkstyle");
}
xg.closeTag("checkstyle");
}
finally
{
xg.close();
}
srcfilename = tmp.getPath();
aggregate = true;
}
else
{
if (!new File(srcfilename).exists())
{
MLogger.err("CheckStyle: No result file found. Exiting.");
return;
}
// erst an dieser Stelle, also nach dem Test, ob die Quelldatei existiert
File ddir = new File(dstdir);
ddir.mkdirs();
}
String dstdirfs = dstdir + "/";
for (int i = 0; i < CHECKSTYLE_FILES.length; i++)
{
String fn = CHECKSTYLE_FILES[i];
FileUtils.copy(new FileOutputStream(dstdirfs + fn), CheckStyleRunner.class.getResourceAsStream("/" + CHECKSTYLE_RESOURCE_DIR + fn), true);
}
MLogger.inf("");
MLogger.inf("Converter/Transformer System Version " + ConvRunner.VERSION + " (CheckStyleRunner)");
MLogger.inf("Copyright (c) " + ConvRunner.COPYRIGHT + " " + ConvRunner.COMPANY + " (StA)");
MLogger.inf("");
try
{
ConvRunner.runConv(".", srcfilename, dstdirfs + "checkstyle_frm.xsl(PrjName=" + prjname + ")", null, dstdirfs + "checkstyle_errors_frm.xml");
ConvRunner.runConv(".", dstdirfs + "checkstyle_errors_frm.xml", dstdirfs + "report_frm_htm.xsl", null, dstdirfs + "checkstyle" + (aggregate ? "-aggregate" : "") + ".htm");
ConvRunner.runConv(".", dstdirfs + "checkstyle_errors_frm.xml", dstdirfs + "report_frm_fo.xsl(ImgPath=" + dstdir + ");FOP", null, dstdirfs + "checkstyle" + (aggregate ? "-aggregate" : "") + ".pdf");
}
catch (Exception ex)
{
MLogger.err("", ex);
}
for (int i = 0; i < CHECKSTYLE_FILES.length; i++)
{
String fn = CHECKSTYLE_FILES[i];
if (fn.endsWith(".xsl"))
{
new File(dstdirfs + fn).delete();
}
}
if (aggregate)
{
new File(srcfilename).delete();
}
new File(dstdirfs + "checkstyle_errors_frm.xml").delete();
}
finally
{
MLogger.removeMLogEntryTS(mle);
}
}
//===========================================================================
/**
* Dummy-Constructor.
*/
protected CheckStyleRunner()
{
}
}