Skip to content

Commit

Permalink
Added -gv option to allow for specification of Graphviz install direc…
Browse files Browse the repository at this point in the history
…tory
  • Loading branch information
johncurrier committed Aug 17, 2009
1 parent 48c861b commit 95ee2f9
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 36 deletions.
9 changes: 8 additions & 1 deletion dist/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
Graphvis is not required to view the output generated by SchemaSpy, but
the <span style="font-style: italic;">dot</span> program should be in your PATH
(not CLASSPATH) when running SchemaSpy or none of the entity relationship diagrams
will be generated.
will be generated (or use the <a href='#gvparam'><code>-gv</code></a> option).
<p>SchemaSpy uses JDBC's database metadata extraction services to gather
the majority of its information, but has to make vendor-specific SQL queries
to gather some information such as the SQL associated with a view and the
Expand Down Expand Up @@ -202,6 +202,13 @@
The drivers are usually contained in .jar or .zip files and are typically
provided by your database vendor.</td>
</tr>
<tr id="gvparam">
<td>&nbsp;</td>
<td class="param"><code>-gv <i>pathToGraphviz</i></code></td>
<td class="param">By default SchemaSpy expects the dot executable to be
in the PATH environment variable.
Use this option to explicitly specify where Graphviz is installed.</td>
</tr>
<tr id="descparam">
<td>&nbsp;</td>
<td class="param"><code>-desc <i>"Schema description"</i></code></td>
Expand Down
5 changes: 5 additions & 0 deletions dist/releaseNotes.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ <h3><a href='http://schemaspy.sourceforge.net'>SchemaSpy</a> Release Notes</h3>
they support schemas but really don't (e.g. older versions of Informix).<br>
Thanks to Joao Batalha for reporting the problem.
</li>
<li>There were scenarios where SchemaSpy had difficultly resolving
the dot executable though the PATH environment variable.
Added a -gv option to optionally remove the dependency on having your PATH
include Graphviz's bin directory.
</li>
</ul>
</li>

Expand Down
48 changes: 48 additions & 0 deletions src/net/sourceforge/schemaspy/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class Config
private boolean helpRequired;
private boolean dbHelpRequired;
private File outputDir;
private File graphvizDir;
private String dbType;
private String schema;
private List<String> schemas;
Expand Down Expand Up @@ -180,6 +181,49 @@ public File getOutputDir() {
return outputDir;
}

/**
* Set the path to Graphviz so we can find dot to generate ER diagrams
*
* @param graphvizDir
*/
public void setGraphvizDir(String graphvizDir) {
if (graphvizDir.endsWith("\""))
graphvizDir = graphvizDir.substring(0, graphvizDir.length() - 1);

setGraphvizDir(new File(graphvizDir));
}

/**
* Set the path to Graphviz so we can find dot to generate ER diagrams
*
* @param graphvizDir
*/
public void setGraphvizDir(File graphvizDir) {
this.graphvizDir = graphvizDir;
}

/**
* Return the path to Graphviz (used to find the dot executable to run to
* generate ER diagrams).<p/>
*
* Returns {@link #getDefaultGraphvizPath()} if a specific Graphviz path
* was not specified.
*
* @return
*/
public File getGraphvizDir() {
if (graphvizDir == null) {
String gv = pullParam("-gv");
if (gv != null) {
setGraphvizDir(gv);
} else {
// expect to find Graphviz's bin directory on the PATH
}
}

return graphvizDir;
}

/**
* Meta files are XML-based files that provide additional metadata
* about the schema being evaluated.<p>
Expand Down Expand Up @@ -1455,6 +1499,10 @@ public List<String> asList() throws IOException {
params.add("-meta");
params.add(value);
}
if (getGraphvizDir() != null) {
params.add("-gv");
params.add(getGraphvizDir().toString());
}
params.add("-i");
params.add(getTableInclusions().pattern());
params.add("-I");
Expand Down
105 changes: 71 additions & 34 deletions src/net/sourceforge/schemaspy/util/Dot.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,47 @@
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.schemaspy.Config;

public class Dot {
private static Dot instance = new Dot();
private final Version version;
private final Version supportedVersion = new Version("2.2.1");
private final Version badVersion = new Version("2.4");
private final String lineSeparator = System.getProperty("line.separator");
private String dotExe;
private String format = "png";
private String renderer;
private Set<String> validatedRenderers = Collections.synchronizedSet(new HashSet<String>());
private Set<String> invalidatedRenderers = Collections.synchronizedSet(new HashSet<String>());
private final Set<String> validatedRenderers = Collections.synchronizedSet(new HashSet<String>());
private final Set<String> invalidatedRenderers = Collections.synchronizedSet(new HashSet<String>());

private Dot() {
String versionText = null;
// dot -V should return something similar to:
// dot version 2.8 (Fri Feb 3 22:38:53 UTC 2006)
// or sometimes something like:
// dot - Graphviz version 2.9.20061004.0440 (Wed Oct 4 21:01:52 GMT 2006)
String[] dotCommand = new String[] { getExe(), "-V" };

try {
// dot -V should return something similar to:
// dot version 2.8 (Fri Feb 3 22:38:53 UTC 2006)
// or sometimes something like:
// dot - Graphviz version 2.9.20061004.0440 (Wed Oct 4 21:01:52 GMT 2006)
String dotCommand = "dot -V";
Process process = Runtime.getRuntime().exec(dotCommand);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String versionLine = reader.readLine();

// look for a number followed numbers or dots
Matcher matcher = Pattern.compile("[0-9][0-9.]+").matcher(versionLine);
if (matcher.find()) {
versionText = matcher.group();
} else {
System.err.println();
System.err.println("Invalid dot configuration detected. '" + dotCommand + "' returned:");
System.err.println("Invalid dot configuration detected. '" +
getDisplayableCommand(dotCommand) + "' returned:");
System.err.println(" " + versionLine);
}
} catch (Exception validDotDoesntExist) {
System.err.println("Failed to query Graphviz version information: " + validDotDoesntExist);
System.err.println("Failed to query Graphviz version information");
System.err.println(" with: " + getDisplayableCommand(dotCommand));
System.err.println(" " + validDotDoesntExist);
}

version = new Version(versionText);
Expand Down Expand Up @@ -78,7 +84,7 @@ public boolean supportsCenteredEastWestEdges() {
* Set the image format to generate. Defaults to <code>png</code>.
* See <a href='http://www.graphviz.org/doc/info/output.html'>http://www.graphviz.org/doc/info/output.html</a>
* for valid formats.
*
*
* @param format image format to generate
*/
public void setFormat(String format) {
Expand All @@ -92,44 +98,44 @@ public void setFormat(String format) {
public String getFormat() {
return format;
}

/**
* Returns true if the installed dot requires specifying :gd as a renderer.
* This was added when Win 2.15 came out because it defaulted to Cairo, which produces
* better quality output, but at a significant speed and size penalty.<p>
*
*
* The intent of this property is to determine if it's ok to tack ":gd" to
* the format specifier. Earlier versions didn't require it and didn't know
* about the option.
*
*
* @return
*/
public boolean requiresGdRenderer() {
return getVersion().compareTo(new Version("2.12")) >= 0 && supportsRenderer(":gd");
}

/**
* Set the renderer to use for the -Tformat[:renderer[:formatter]] dot option as specified
* at <a href='http://www.graphviz.org/doc/info/command.html'>
* http://www.graphviz.org/doc/info/command.html</a> where "format" is specified by
* {@link #setFormat(String)}<p>
* Note that the leading ":" is required while :formatter is optional.
*
*
* @param renderer
*/
public void setRenderer(String renderer) {
this.renderer = renderer;
}

public String getRenderer() {
return renderer != null && supportsRenderer(renderer) ? renderer
return renderer != null && supportsRenderer(renderer) ? renderer
: (requiresGdRenderer() ? ":gd" : "");
}

/**
* If <code>true</code> then generate output of "higher quality"
* than the default ("lower quality").
* Note that the default is intended to be "lower quality",
* than the default ("lower quality").
* Note that the default is intended to be "lower quality",
* but various installations of Graphviz may have have different abilities.
* That is, some might not have the "lower quality" libraries and others might
* not have the "higher quality" libraries.
Expand All @@ -148,27 +154,30 @@ public void setHighQuality(boolean highQuality) {
public boolean isHighQuality() {
return getRenderer().indexOf(":cairo") != -1;
}

/**
* Returns <code>true</code> if the specified renderer is supported.
* See {@link #setRenderer(String)} for renderer details.
*
*
* @param renderer
* @return
*/
public boolean supportsRenderer(@SuppressWarnings("hiding") String renderer) {
if (!exists())
return false;

if (validatedRenderers.contains(renderer))
return true;

if (invalidatedRenderers.contains(renderer))
return false;

try {
String[] dotParams = new String[] {"dot", "-T" + getFormat() + ':'};
Process process = Runtime.getRuntime().exec(dotParams);
String[] dotCommand = new String[] {
getExe(),
"-T" + getFormat() + ':'
};
Process process = Runtime.getRuntime().exec(dotCommand);
BufferedReader errors = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line;
while ((line = errors.readLine()) != null) {
Expand All @@ -180,30 +189,58 @@ public boolean supportsRenderer(@SuppressWarnings("hiding") String renderer) {
} catch (Exception exc) {
exc.printStackTrace();
}

if (!validatedRenderers.contains(renderer)) {
//System.err.println("\nFailed to validate " + getFormat() + " renderer '" + renderer + "'. Reverting to detault renderer for " + getFormat() + '.');
invalidatedRenderers.add(renderer);
return false;
}

return true;
}

/**
* Returns the executable to use to run dot
*
* @return
*/
private String getExe() {
if (dotExe == null)
{
File gv = Config.getInstance().getGraphvizDir();

if (gv == null) {
// default to finding dot in the PATH
dotExe = "dot";
} else {
// pull dot from the Graphviz bin directory specified
dotExe = new File(new File(gv, "bin"), "dot").toString();
}
}

return dotExe;
}

/**
* Using the specified .dot file generates an image returning the image's image map.
*/
public String generateDiagram(File dotFile, File diagramFile) throws DotFailure {
StringBuilder mapBuffer = new StringBuilder(1024);

BufferedReader mapReader = null;
// this one is for executing. it can (hopefully) deal with funky things in filenames.
String[] dotParams = new String[] {"dot", "-T" + getFormat() + getRenderer(), dotFile.toString(), "-o" + diagramFile, "-Tcmapx"};
String[] dotCommand = new String[] {
getExe(),
"-T" + getFormat() + getRenderer(),
dotFile.toString(),
"-o" + diagramFile,
"-Tcmapx"
};
// this one is for display purposes ONLY.
String commandLine = getDisplayableCommand(dotParams);
String commandLine = getDisplayableCommand(dotCommand);

try {
Process process = Runtime.getRuntime().exec(dotParams);
Process process = Runtime.getRuntime().exec(dotCommand);
new ProcessOutputReader(commandLine, process.getErrorStream()).start();
mapReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
Expand Down
3 changes: 2 additions & 1 deletion src/net/sourceforge/schemaspy/view/HtmlDiagramFormatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ protected Dot getDot() {
System.err.println();
System.err.println("Warning: Failed to run dot.");
System.err.println(" Download " + dot.getSupportedVersions());
System.err.println(" from www.graphviz.org and make sure that dot is in your path.");
System.err.println(" from www.graphviz.org and make sure that dot is either in your path");
System.err.println(" or point to where you installed Graphviz with the -gv option.");
System.err.println(" Generated pages will not contain a diagramtic view of table relationships.");
}

Expand Down

0 comments on commit 95ee2f9

Please sign in to comment.