Repository: workcraft/workcraft
Issue: Petrify issue if installed in a non-user-writable directory

Using Workcraft V3.1.2 on Arch Linux.

With a basic STG, selecting `Tools -> External visualizer -> State graph ({basic,binary-coded})` fails when the directory `workcraft/Tools/PetrifyTools` is not writable by the user who invoked `workcraft`. The error is:

> Petrify tool chain execution failed.
> 
> Errors running draw_astg:
> **\\* FATAL ERROR: opening tmp file <draw_astg_xxxxxx>

A zero-size pdf is produced by draw_astg in the tmp directory. Using `strace` it seems that Petrify's `write_sg` does not finish writing the .sg file before `draw_astg` is called under these conditions. I'm not sure if this is something to do with Petrify being unable to write its log file (which should reside in the unwritable directory I believe).

I have not found this to happen for any other Petrify task such as from the `verification` or `conversion` menus under these conditions. The tasks stated above seem to be the only ones which perform two Petrify operations with the second depending on the first (at least when working with an STG).

This came to my attention when packaging Workcraft where the files will normally reside in `/opt` or `/usr/share` which are owned root:root with 755 permissions (ie. not writable by a normal user who would invoke `workcraft`). In this situation, allowing write permissions for "other" would not be a permissible solution.


Changed files:
PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/DrawAstgTask.java, PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/AstgExporter.java, FstPlugin/src/org/workcraft/plugins/fst/task/WriteSgConversionTask.java, PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/DrawSgTask.java, WorkcraftCore/src/org/workcraft/Info.java, PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/WriteSgTask.java

diff --git a/FstPlugin/src/org/workcraft/plugins/fst/task/WriteSgConversionTask.java b/FstPlugin/src/org/workcraft/plugins/fst/task/WriteSgConversionTask.java
index 08cf8b9e1..44251be2d 100644
--- a/FstPlugin/src/org/workcraft/plugins/fst/task/WriteSgConversionTask.java
+++ b/FstPlugin/src/org/workcraft/plugins/fst/task/WriteSgConversionTask.java
@@ -105,7 +105,7 @@ public class WriteSgConversionTask implements Task<WriteSgConversionResult> {
             }
 
             while (true) {
-                WriteSgTask writeSgTask = new WriteSgTask(petriFile.getAbsolutePath(), null, writeSgOptions);
+                WriteSgTask writeSgTask = new WriteSgTask(writeSgOptions, petriFile, null, null);
                 Result<? extends ExternalProcessResult> writeSgResult = framework.getTaskManager().execute(
                         writeSgTask, "Building state graph", subtaskMonitor);
 
diff --git a/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/AstgExporter.java b/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/AstgExporter.java
index 4606882c2..a65f63f86 100644
--- a/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/AstgExporter.java
+++ b/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/AstgExporter.java
@@ -82,7 +82,7 @@ public class AstgExporter implements Exporter {
 
         File resultFile = new File(directory, RESULT_FILE_NAME);
 
-        DrawAstgTask task = new DrawAstgTask(stgFile.getAbsolutePath(), resultFile.getAbsolutePath(), new ArrayList<String>());
+        DrawAstgTask task = new DrawAstgTask(new ArrayList<String>(), stgFile, resultFile, directory);
 
         final Result<? extends ExternalProcessResult> drawAstgResult = framework.getTaskManager().execute(task, "Executing Petrify");
 
diff --git a/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/DrawAstgTask.java b/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/DrawAstgTask.java
index 586739c50..12c3dce7e 100644
--- a/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/DrawAstgTask.java
+++ b/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/DrawAstgTask.java
@@ -1,5 +1,6 @@
 package org.workcraft.plugins.petrify.tasks;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -13,13 +14,16 @@ import org.workcraft.tasks.Task;
 import org.workcraft.util.ToolUtils;
 
 public class DrawAstgTask implements Task<ExternalProcessResult> {
-    private final String inputPath, outputPath;
     private final List<String> options;
+    private final File inputFile;
+    private final File outputFile;
+    private final File workingDirectory;
 
-    public DrawAstgTask(String inputPath, String outputPath, List<String> options) {
-        this.inputPath = inputPath;
-        this.outputPath = outputPath;
+    public DrawAstgTask(List<String> options, File inputFile, File outputFile, File workingDirectory) {
         this.options = options;
+        this.inputFile = inputFile;
+        this.outputFile = outputFile;
+        this.workingDirectory = workingDirectory;
     }
 
     @Override
@@ -36,13 +40,17 @@ public class DrawAstgTask implements Task<ExternalProcessResult> {
         }
 
         // Input file
-        command.add(inputPath);
+        if (inputFile != null) {
+            command.add(inputFile.getAbsolutePath());
+        }
 
         // Output file
-        command.add("-o");
-        command.add(outputPath);
+        if (outputFile != null) {
+            command.add("-o");
+            command.add(outputFile.getAbsolutePath());
+        }
 
-        ExternalProcessTask task = new ExternalProcessTask(command, null);
+        ExternalProcessTask task = new ExternalProcessTask(command, workingDirectory);
         Result<? extends ExternalProcessResult> res = task.run(monitor);
 
         if (res.getOutcome() != Outcome.FINISHED) {
diff --git a/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/DrawSgTask.java b/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/DrawSgTask.java
index a639f68d1..245ba2d0e 100644
--- a/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/DrawSgTask.java
+++ b/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/DrawSgTask.java
@@ -96,7 +96,7 @@ public class DrawSgTask implements Task<DrawSgResult> {
                 writeSgOptions.add("-bin");
             }
             while (true) {
-                WriteSgTask writeSgTask = new WriteSgTask(stgFile.getAbsolutePath(), sgFile.getAbsolutePath(), writeSgOptions);
+                WriteSgTask writeSgTask = new WriteSgTask(writeSgOptions, stgFile, sgFile, directory);
                 Result<? extends ExternalProcessResult> writeSgResult = framework.getTaskManager().execute(
                         writeSgTask, "Running Petrify");
 
@@ -133,7 +133,7 @@ public class DrawSgTask implements Task<DrawSgResult> {
             if (binary) {
                 drawAstgOptions.add("-bin");
             }
-            DrawAstgTask drawAstgTask = new DrawAstgTask(sgFile.getAbsolutePath(), resultFile.getAbsolutePath(), drawAstgOptions);
+            DrawAstgTask drawAstgTask = new DrawAstgTask(drawAstgOptions, sgFile, resultFile, directory);
             final Result<? extends ExternalProcessResult> drawAstgResult = framework.getTaskManager().execute(drawAstgTask, "Running Petrify");
 
             if (drawAstgResult.getOutcome() != Outcome.FINISHED) {
diff --git a/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/WriteSgTask.java b/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/WriteSgTask.java
index d8401b526..a879434ee 100644
--- a/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/WriteSgTask.java
+++ b/PetrifyExtraPlugin/src/org/workcraft/plugins/petrify/tasks/WriteSgTask.java
@@ -1,5 +1,6 @@
 package org.workcraft.plugins.petrify.tasks;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -16,18 +17,21 @@ import org.workcraft.util.DataAccumulator;
 import org.workcraft.util.ToolUtils;
 
 public class WriteSgTask implements Task<ExternalProcessResult>, ExternalProcessListener {
-    private final String inputPath, outputPath;
     private final List<String> options;
+    private final File inputFile;
+    private final File outputFile;
+    private final File workingDirectory;
 
     private ProgressMonitor<? super ExternalProcessResult> monitor;
 
     private final DataAccumulator stdoutAccum = new DataAccumulator();
     private final DataAccumulator stderrAccum = new DataAccumulator();
 
-    public WriteSgTask(String inputPath, String outputPath, List<String> options) {
-        this.inputPath = inputPath;
-        this.outputPath = outputPath;
+    public WriteSgTask(List<String> options, File inputFile, File outputFile, File workingDirectory) {
         this.options = options;
+        this.inputFile = inputFile;
+        this.outputFile = outputFile;
+        this.workingDirectory = workingDirectory;
     }
 
     @Override
@@ -47,17 +51,17 @@ public class WriteSgTask implements Task<ExternalProcessResult>, ExternalProcess
         }
 
         // Input file
-        if ((inputPath != null) && !inputPath.isEmpty()) {
-            command.add(inputPath);
+        if (inputFile != null) {
+            command.add(inputFile.getAbsolutePath());
         }
 
         // Output file
-        if ((outputPath != null) && !outputPath.isEmpty()) {
+        if (outputFile != null) {
             command.add("-o");
-            command.add(outputPath);
+            command.add(outputFile.getAbsolutePath());
         }
 
-        ExternalProcessTask task = new ExternalProcessTask(command, null);
+        ExternalProcessTask task = new ExternalProcessTask(command, workingDirectory);
         Result<? extends ExternalProcessResult> res = task.run(monitor);
         if (res.getOutcome() != Outcome.FINISHED) {
             return res;
diff --git a/WorkcraftCore/src/org/workcraft/Info.java b/WorkcraftCore/src/org/workcraft/Info.java
index a63f2702d..cc733d205 100644
--- a/WorkcraftCore/src/org/workcraft/Info.java
+++ b/WorkcraftCore/src/org/workcraft/Info.java
@@ -12,8 +12,8 @@ public class Info {
 
     private static final int majorVersion = 3;
     private static final int minorVersion = 1;
-    private static final int revisionVersion = 2;
-    private static final String statusVersion = null; // "alpha", "beta", "rc1", null (for release)
+    private static final int revisionVersion = 3;
+    private static final String statusVersion = "alpha"; // "alpha", "beta", "rc1", null (for release)
 
     private static final int startYear = 2006;
     private static final int currentYear = Calendar.getInstance().get(Calendar.YEAR);