diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index f59a1dfa8..6b74e80ad 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -32,6 +32,7 @@ import cc.arduino.contributions.packages.ContributionInstaller; import cc.arduino.contributions.packages.ContributionsIndexer; import cc.arduino.contributions.DownloadableContributionVersionComparator; import cc.arduino.contributions.packages.ui.ContributionManagerUI; +import cc.arduino.files.DeleteFilesOnShutdown; import cc.arduino.packages.DiscoveryManager; import cc.arduino.utils.Progress; import cc.arduino.view.SplashScreenHelper; @@ -127,6 +128,8 @@ public class Base { } static public void guardedMain(String args[]) throws Exception { + Runtime.getRuntime().addShutdownHook(new Thread(DeleteFilesOnShutdown.INSTANCE)); + BaseNoGui.initLogger(); BaseNoGui.notifier = new GUIUserNotifier(); @@ -202,7 +205,7 @@ public class Base { // Create a location for untitled sketches untitledFolder = createTempFolder("untitled"); - untitledFolder.deleteOnExit(); + DeleteFilesOnShutdown.add(untitledFolder); new Base(args); } @@ -401,6 +404,7 @@ public class Base { // Set verbosity for command line build Preferences.set("build.verbose", "" + parser.isDoVerboseBuild()); Preferences.set("upload.verbose", "" + parser.isDoVerboseUpload()); + Preferences.set("runtime.preserve.temp.files", Boolean.toString(parser.isPreserveTempFiles())); // Make sure these verbosity preferences are only for the // current session diff --git a/app/src/processing/app/EditorConsoleStream.java b/app/src/processing/app/EditorConsoleStream.java index 06e232673..cfe78fd66 100644 --- a/app/src/processing/app/EditorConsoleStream.java +++ b/app/src/processing/app/EditorConsoleStream.java @@ -1,5 +1,7 @@ package processing.app; +import cc.arduino.files.DeleteFilesOnShutdown; + import static processing.app.I18n._; import java.io.File; @@ -33,19 +35,19 @@ class EditorConsoleStream extends OutputStream { // The files and folders are not deleted on exit because they may be // needed for debugging or bug reporting. tempFolder = Base.createTempFolder("console"); - tempFolder.deleteOnExit(); + DeleteFilesOnShutdown.add(tempFolder); try { String outFileName = Preferences.get("console.output.file"); if (outFileName != null) { outFile = new File(tempFolder, outFileName); - outFile.deleteOnExit(); + DeleteFilesOnShutdown.add(outFile); stdoutFile = new FileOutputStream(outFile); } String errFileName = Preferences.get("console.error.file"); if (errFileName != null) { errFile = new File(tempFolder, errFileName); - errFile.deleteOnExit(); + DeleteFilesOnShutdown.add(errFile); stderrFile = new FileOutputStream(errFile); } } catch (IOException e) { diff --git a/app/test/processing/app/AbstractGUITest.java b/app/test/processing/app/AbstractGUITest.java index 1568db5d1..60e702bce 100644 --- a/app/test/processing/app/AbstractGUITest.java +++ b/app/test/processing/app/AbstractGUITest.java @@ -1,5 +1,6 @@ package processing.app; +import cc.arduino.files.DeleteFilesOnShutdown; import org.fest.swing.edt.FailOnThreadViolationRepaintManager; import org.fest.swing.edt.GuiActionRunner; import org.fest.swing.edt.GuiQuery; @@ -16,6 +17,7 @@ public abstract class AbstractGUITest { @Before public void startUpTheIDE() throws Exception { System.setProperty("mrj.version", "whynot"); //makes sense only on osx. See https://github.com/alexruiz/fest-swing-1.x/issues/2#issuecomment-86532042 + Runtime.getRuntime().addShutdownHook(new Thread(DeleteFilesOnShutdown.INSTANCE)); FailOnThreadViolationRepaintManager.install(); @@ -25,7 +27,7 @@ public abstract class AbstractGUITest { Theme.init(); Base.getPlatform().setLookAndFeel(); Base.untitledFolder = Base.createTempFolder("untitled"); - Base.untitledFolder.deleteOnExit(); + DeleteFilesOnShutdown.add(Base.untitledFolder); window = GuiActionRunner.execute(new GuiQuery() { @Override diff --git a/app/test/processing/app/AbstractWithPreferencesTest.java b/app/test/processing/app/AbstractWithPreferencesTest.java index ca07ec385..cabf9ec11 100644 --- a/app/test/processing/app/AbstractWithPreferencesTest.java +++ b/app/test/processing/app/AbstractWithPreferencesTest.java @@ -1,17 +1,19 @@ package processing.app; +import cc.arduino.files.DeleteFilesOnShutdown; import org.junit.Before; public abstract class AbstractWithPreferencesTest { @Before public void init() throws Exception { + Runtime.getRuntime().addShutdownHook(new Thread(DeleteFilesOnShutdown.INSTANCE)); Base.initPlatform(); Preferences.init(null); Theme.init(); Base.untitledFolder = Base.createTempFolder("untitled"); - Base.untitledFolder.deleteOnExit(); - + DeleteFilesOnShutdown.add(Base.untitledFolder); } + } diff --git a/arduino-core/src/cc/arduino/files/DeleteFilesOnShutdown.java b/arduino-core/src/cc/arduino/files/DeleteFilesOnShutdown.java new file mode 100644 index 000000000..7d9f60139 --- /dev/null +++ b/arduino-core/src/cc/arduino/files/DeleteFilesOnShutdown.java @@ -0,0 +1,47 @@ +package cc.arduino.files; + +import processing.app.PreferencesData; +import processing.app.helpers.FileUtils; + +import java.io.File; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class DeleteFilesOnShutdown implements Runnable { + + public static final DeleteFilesOnShutdown INSTANCE = new DeleteFilesOnShutdown(); + + public static void add(File file) { + INSTANCE.addFile(file); + } + + private final List files; + + public DeleteFilesOnShutdown() { + this.files = new LinkedList(); + } + + public synchronized void addFile(File file) { + this.files.add(file); + } + + @Override + public void run() { + boolean preserveTempFiles = PreferencesData.getBoolean("runtime.preserve.temp.files"); + if (preserveTempFiles) { + return; + } + List copyOfFiles; + synchronized (this) { + copyOfFiles = new LinkedList(files); + } + Collections.reverse(copyOfFiles); + for (File file : copyOfFiles) { + if (file.exists() && file.canWrite()) { + FileUtils.recursiveDelete(file); + } + } + } + +} diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java index aaa7eaa0e..e7a08c261 100644 --- a/arduino-core/src/processing/app/BaseNoGui.java +++ b/arduino-core/src/processing/app/BaseNoGui.java @@ -1,11 +1,11 @@ package processing.app; import cc.arduino.contributions.libraries.LibrariesIndexer; +import cc.arduino.files.DeleteFilesOnShutdown; import cc.arduino.packages.DiscoveryManager; import cc.arduino.packages.Uploader; import cc.arduino.contributions.packages.ContributedTool; import cc.arduino.contributions.packages.ContributionsIndexer; -import cc.arduino.utils.ArchiveExtractor; import org.apache.commons.logging.impl.LogFactoryImpl; import org.apache.commons.logging.impl.NoOpLog; import processing.app.debug.Compiler; @@ -133,7 +133,7 @@ public class BaseNoGui { //File folder = new File(getTempFolder(), "build"); //if (!folder.exists()) folder.mkdirs(); buildFolder = createTempFolder("build"); - buildFolder.deleteOnExit(); + DeleteFilesOnShutdown.add(buildFolder); } } return buildFolder; @@ -703,6 +703,8 @@ public class BaseNoGui { if (args.length == 0) showError(_("No parameters"), _("No command line parameters found"), null); + Runtime.getRuntime().addShutdownHook(new Thread(DeleteFilesOnShutdown.INSTANCE)); + initPlatform(); initPortableFolder(); diff --git a/arduino-core/src/processing/app/helpers/CommandlineParser.java b/arduino-core/src/processing/app/helpers/CommandlineParser.java index d0e314bcd..2e66e6361 100644 --- a/arduino-core/src/processing/app/helpers/CommandlineParser.java +++ b/arduino-core/src/processing/app/helpers/CommandlineParser.java @@ -36,6 +36,7 @@ public class CommandlineParser { private boolean doVerboseBuild = false; private boolean doVerboseUpload = false; private boolean doUseProgrammer = false; + private boolean preserveTempFiles; private boolean noUploadPort = false; private boolean forceSavePrefs = false; private String getPref; @@ -105,6 +106,12 @@ public class CommandlineParser { action = ACTION.NOOP; continue; } + if (args[i].equals("--preserve-temp-files")) { + preserveTempFiles = true; + if (action == ACTION.GUI) + action = ACTION.NOOP; + continue; + } if (args[i].equals("--verbose-build")) { doVerboseBuild = true; if (action == ACTION.GUI) @@ -330,4 +337,8 @@ public class CommandlineParser { public String getLibraryToInstall() { return libraryToInstall; } + + public boolean isPreserveTempFiles() { + return preserveTempFiles; + } } diff --git a/build/shared/manpage.adoc b/build/shared/manpage.adoc index 4572c5480..5c17d1521 100644 --- a/build/shared/manpage.adoc +++ b/build/shared/manpage.adoc @@ -25,7 +25,7 @@ SYNOPSIS -------- *arduino* ['FILE.ino'...] -*arduino* [*--verify*|*--upload*] [*--board* __package__:__arch__:__board__[:__parameters__]] [*--port* __portname__] [*--pref* __name__=__value__] [*-v*|*--verbose*] [__FILE.ino__] +*arduino* [*--verify*|*--upload*] [*--board* __package__:__arch__:__board__[:__parameters__]] [*--port* __portname__] [*--pref* __name__=__value__] [*-v*|*--verbose*] [--preserve-temp-files] [__FILE.ino__] *arduino* [*--get-pref* __preference__] @@ -117,6 +117,10 @@ OPTIONS verbose mode during build is *disabled* regardless of the current preferences. +*--preserve-temp-files*:: + Keep temporary files (preprocessed sketch, object files...) after termination. + If omitted, temporary files are deleted. + {empty}:: This option is only valid together with *--verify* or *--upload*.