From 92aa64f6c25cb2ee381e0e2af29f8d360448bb28 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 09:51:25 +0200 Subject: [PATCH 01/25] Use an "action" enum when processing commandline arguments Previously, two separate booleans (doUpload and doVerify) were used. However, since it always makes sense to specify only one of them, it makes more sense to keep a single action enum variable, which slightly simplifies the code (especially when more actions are added later). Additionally, an error is now shown when both --verify and --upload are specified on the commandline. --- app/src/processing/app/Base.java | 33 +++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index c0806157ec4..c259f306175 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -268,6 +268,7 @@ static protected void initRequirements() { } + protected static enum ACTION { GUI, VERIFY, UPLOAD }; public Base(String[] args) throws Exception { platform.init(this); @@ -318,8 +319,7 @@ public Base(String[] args) throws Exception { // Setup board-dependent variables. onBoardOrPortChange(); - boolean doUpload = false; - boolean doVerify = false; + ACTION action = ACTION.GUI; boolean doVerboseBuild = false; boolean doVerboseUpload = false;; String selectBoard = null; @@ -327,14 +327,21 @@ public Base(String[] args) throws Exception { String currentDirectory = System.getProperty("user.dir"); List filenames = new LinkedList(); + // Map of possible actions and corresponding options + final Map actions = new HashMap(); + actions.put("--verify", ACTION.VERIFY); + actions.put("--upload", ACTION.UPLOAD); + // Check if any files were passed in on the command line for (int i = 0; i < args.length; i++) { - if (args[i].equals("--upload")) { - doUpload = true; - continue; - } - if (args[i].equals("--verify")) { - doVerify = true; + ACTION a = actions.get(args[i]); + if (a != null) { + if (action != ACTION.GUI) { + String[] valid = actions.keySet().toArray(new String[0]); + String mess = I18n.format(_("Can only pass one of: {0}"), PApplet.join(valid, ", ")); + showError(null, mess, 3); + } + action = a; continue; } if (args[i].equals("--verbose") || args[i].equals("-v")) { @@ -391,7 +398,7 @@ public Base(String[] args) throws Exception { filenames.add(args[i]); } - if ((doUpload || doVerify) && filenames.size() != 1) + if ((action == ACTION.UPLOAD || action == ACTION.VERIFY) && filenames.size() != 1) showError(null, _("Must specify exactly one sketch file"), 3); for (String path: filenames) { @@ -412,17 +419,17 @@ public Base(String[] args) throws Exception { path = new File(currentDirectory, path).getAbsolutePath(); } - if (handleOpen(path, nextEditorLocation(), !(doUpload || doVerify)) == null) { + if (handleOpen(path, nextEditorLocation(), !(action == ACTION.UPLOAD || action == ACTION.VERIFY)) == null) { String mess = I18n.format(_("Failed to open sketch: \"{0}\""), path); // Open failure is fatal in upload/verify mode - if (doUpload || doVerify) + if (action == ACTION.VERIFY || action == ACTION.UPLOAD) showError(null, mess, 2); else showWarning(null, mess, null); } } - if (doUpload || doVerify) { + if (action == ACTION.UPLOAD || action == ACTION.VERIFY) { // Set verbosity for command line build Preferences.set("build.verbose", "" + doVerboseBuild); Preferences.set("upload.verbose", "" + doVerboseUpload); @@ -432,7 +439,7 @@ public Base(String[] args) throws Exception { // Do board selection if requested processBoardArgument(selectBoard); - if (doUpload) { + if (action == ACTION.UPLOAD) { // Build and upload if (selectPort != null) editor.selectSerialPort(selectPort); From 0453606cbf529866ef5fdbf112782b350cb72598 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 10:01:41 +0200 Subject: [PATCH 02/25] Invert decision on when to show the GUI Previously, the code showed an error when the given action was not upload or verify. This is now reversed: the GUI is shown when the action is "GUI" (which is the default when no action specified). Since the action enum only contains these three values, there is no change in behaviour, but this makes it easier to add new actions later. --- app/src/processing/app/Base.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index c259f306175..8b3618b0ef7 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -419,7 +419,8 @@ public Base(String[] args) throws Exception { path = new File(currentDirectory, path).getAbsolutePath(); } - if (handleOpen(path, nextEditorLocation(), !(action == ACTION.UPLOAD || action == ACTION.VERIFY)) == null) { + boolean showEditor = (action == ACTION.GUI); + if (handleOpen(path, nextEditorLocation(), showEditor) == null) { String mess = I18n.format(_("Failed to open sketch: \"{0}\""), path); // Open failure is fatal in upload/verify mode if (action == ACTION.VERIFY || action == ACTION.UPLOAD) From a90cb9de976442f3b7376c0b24886987ca1cc07d Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 10:06:48 +0200 Subject: [PATCH 03/25] Improve commandline handling control flow This uses a switch on the action value, which makes it more clear what code runs when. No actual behaviour is changed, most of the changes in this commit are indentation changes. --- app/src/processing/app/Base.java | 76 +++++++++++++++++--------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 8b3618b0ef7..b022bc71c8b 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -430,46 +430,50 @@ public Base(String[] args) throws Exception { } } - if (action == ACTION.UPLOAD || action == ACTION.VERIFY) { - // Set verbosity for command line build - Preferences.set("build.verbose", "" + doVerboseBuild); - Preferences.set("upload.verbose", "" + doVerboseUpload); - - Editor editor = editors.get(0); - - // Do board selection if requested - processBoardArgument(selectBoard); - - if (action == ACTION.UPLOAD) { - // Build and upload - if (selectPort != null) - editor.selectSerialPort(selectPort); - editor.exportHandler.run(); - } else { - // Build only - editor.runHandler.run(); - } - - // Error during build or upload - int res = editor.status.mode; - if (res == EditorStatus.ERR) - System.exit(1); + switch (action) { + case VERIFY: + case UPLOAD: + // Set verbosity for command line build + Preferences.set("build.verbose", "" + doVerboseBuild); + Preferences.set("upload.verbose", "" + doVerboseUpload); + + Editor editor = editors.get(0); + + // Do board selection if requested + processBoardArgument(selectBoard); + + if (action == ACTION.UPLOAD) { + // Build and upload + if (selectPort != null) + editor.selectSerialPort(selectPort); + editor.exportHandler.run(); + } else { + // Build only + editor.runHandler.run(); + } - // No errors exit gracefully - System.exit(0); - } + // Error during build or upload + int res = editor.status.mode; + if (res == EditorStatus.ERR) + System.exit(1); - // Check if there were previously opened sketches to be restored - restoreSketches(); + // No errors exit gracefully + System.exit(0); + break; + case GUI: + // Check if there were previously opened sketches to be restored + restoreSketches(); - // Create a new empty window (will be replaced with any files to be opened) - if (editors.isEmpty()) { - handleNew(); - } + // Create a new empty window (will be replaced with any files to be opened) + if (editors.isEmpty()) { + handleNew(); + } - // Check for updates - if (Preferences.getBoolean("update.check")) { - new UpdateCheck(this); + // Check for updates + if (Preferences.getBoolean("update.check")) { + new UpdateCheck(this); + } + break; } } From d028a7aea1f0478932a96ca73cce09b8bf333113 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 10:11:57 +0200 Subject: [PATCH 04/25] Add Base.selectSerialPort This method takes care of setting the serial.port preference to the given value, as well as deriving the serial.port.file preference. This should prevent duplicate code in the future. Note that a second copy of this code lives in SerialUploader, but that doesn't write to the global Preferences but a local prefs map. Since the global Preferences are currently static, there is no way to share code between these two copies. --- app/src/processing/app/Base.java | 7 +++++++ app/src/processing/app/Editor.java | 6 +----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index b022bc71c8b..fb869c546fe 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1600,6 +1600,13 @@ private void selectBoard(TargetBoard targetBoard) { rebuildExamplesMenu(Editor.examplesMenu); } + public static void selectSerialPort(String port) { + Preferences.set("serial.port", port); + if (port.startsWith("/dev/")) + Preferences.set("serial.port.file", port.substring(5)); + else + Preferences.set("serial.port.file", port); + } public void rebuildProgrammerMenu(JMenu menu) { menu.removeAll(); diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 278b548409e..9fa785e7090 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -965,11 +965,7 @@ protected void selectSerialPort(String name) { } if (selection != null) selection.setState(true); //System.out.println(item.getLabel()); - Preferences.set("serial.port", name); - if (name.startsWith("/dev/")) - Preferences.set("serial.port.file", name.substring(5)); - else - Preferences.set("serial.port.file", name); + Base.selectSerialPort(name); if (serialMonitor != null) { try { serialMonitor.close(); From 017dc70e56e71566bb8c76b57b32d31e7399e04e Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 11:26:29 +0200 Subject: [PATCH 05/25] Fix indentation in the manpage --- build/shared/manpage.adoc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/build/shared/manpage.adoc b/build/shared/manpage.adoc index 30f5072cdce..cf08b8c27b8 100644 --- a/build/shared/manpage.adoc +++ b/build/shared/manpage.adoc @@ -87,19 +87,19 @@ OPTIONS preferences is used (e.g., the last port selected in the IDE). *--verbose-build*:: - Enable verbose mode during build. If this option is not given, - verbose mode during build is disabled regardless of the current - preferences. + Enable verbose mode during build. If this option is not given, + verbose mode during build is disabled regardless of the current + preferences. *--verbose-upload*:: - Enable verbose mode during upload. If this option is not given, - verbose mode during upload is disabled regardless of the current - preferences. + Enable verbose mode during upload. If this option is not given, + verbose mode during upload is disabled regardless of the current + preferences. *-v, --verbose*:: Enable verbose mode during build and upload. - This option has the same effect of using both *--verbose-build* - and *--verbose-upload*. + This option has the same effect of using both *--verbose-build* + and *--verbose-upload*. *--preferences-file* __filename__:: Read and store preferences from the specified __filename__ instead From f1a3442478b18fe02aa35d594342c61e49e3a53d Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 11:14:08 +0200 Subject: [PATCH 06/25] Added history section to the manpage This describes the versions where various options were introduced or changed. --- build/shared/manpage.adoc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/build/shared/manpage.adoc b/build/shared/manpage.adoc index cf08b8c27b8..0ee60f654e0 100644 --- a/build/shared/manpage.adoc +++ b/build/shared/manpage.adoc @@ -211,6 +211,32 @@ re-use any previous build results in that directory. arduino --pref build.path=/path/to/sketch/build --verify /path/to/sketch/sketch.ino +HISTORY +------- +1.5.2:: + Added initial commandline support. This introduced *--verify*, + *--upload*, *--board*, *--port*, *--verbose* and *-v*. + +1.5.5:: + Added support for board-specific parameters to *--board*. + +{empty}:: + Sketch filenames are now interpreted relative to the current + directory instead of the location of the arduino command itself. + +1.5.6:: + Introduced *--pref*, *--preferences-file*, *--verbose-build* and + *--verbose-upload*. + +{empty}:: + Preferences set through --pref are remembered, preferences set + through *--board*, *--port* or the *--verbose* options are not. + +{empty}:: + When running with *--verify* or *--upload*, the full GUI is no + longer shown. Error messages still use a graphical popup and on + Windows, the splash screen is still shown. + RESOURCES --------- Web site: From 34f59301e674145cd8bf73220fbd897d51f6cfa0 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 10:27:39 +0200 Subject: [PATCH 07/25] Process some commandline arguments earlier Previously, the --board and --port arguments were stored in a variable first and only processed later. Now, the arguments are processed right away. This does mean that the arguments are processed when the GUI is not yet initialized, which caused problems with calling onBoardOrPortChange and friends from selectBoard. However, since the GUI is not initialized, there is no real reason to call them either - if we just set the preferences to the right values, the GUI will be initialized correctly later. For this reason, selectBoard no longer calls the GUI update methods. Instead, those are called from the GUI code when the board is changed through the menu instead (e.g., after calling selectBoard). This commit slightly changes behaviour. Previously, --board and --port only worked in combination with --verify and --upload, but were ignored when just starting the IDE. Now, these are processed regardless of the other options present. Additionally, this commit causes all changed preferences to be saved. Previously, only changes with --pref were saved, --board and --port options were only active for the current run. This was caused because the saving of the preferences happened as a side effect of loading the file in the Editor, but only the --pref option was processed at that time. Note that the --verbose options are still only active for the current run and are only valid combined with --verify or --upload (since they default to non-verbose instead of the current preference). --- app/src/processing/app/Base.java | 20 +++++++------------- build/shared/manpage.adoc | 18 +++++++++++++----- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index fb869c546fe..ef70c4a1d8e 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -361,14 +361,14 @@ public Base(String[] args) throws Exception { i++; if (i >= args.length) showError(null, _("Argument required for --board"), 3); - selectBoard = args[i]; + processBoardArgument(args[i]); continue; } if (args[i].equals("--port")) { i++; if (i >= args.length) showError(null, _("Argument required for --port"), 3); - selectPort = args[i]; + Base.selectSerialPort(args[i]); continue; } if (args[i].equals("--curdir")) { @@ -439,13 +439,8 @@ public Base(String[] args) throws Exception { Editor editor = editors.get(0); - // Do board selection if requested - processBoardArgument(selectBoard); - if (action == ACTION.UPLOAD) { // Build and upload - if (selectPort != null) - editor.selectSerialPort(selectPort); editor.exportHandler.run(); } else { // Build only @@ -1456,6 +1451,11 @@ private JRadioButtonMenuItem createBoardMenusAndCustomMenus( Action action = new AbstractAction(board.getName()) { public void actionPerformed(ActionEvent actionevent) { selectBoard((TargetBoard)getValue("b")); + filterVisibilityOfSubsequentBoardMenus((TargetBoard)getValue("b"), 1); + + onBoardOrPortChange(); + rebuildImportMenu(Editor.importMenu); + rebuildExamplesMenu(Editor.examplesMenu); } }; action.putValue("b", board); @@ -1592,12 +1592,6 @@ private void selectBoard(TargetBoard targetBoard) { File platformFolder = targetPlatform.getFolder(); Preferences.set("runtime.platform.path", platformFolder.getAbsolutePath()); Preferences.set("runtime.hardware.path", platformFolder.getParentFile().getAbsolutePath()); - - filterVisibilityOfSubsequentBoardMenus(targetBoard, 1); - - onBoardOrPortChange(); - rebuildImportMenu(Editor.importMenu); - rebuildExamplesMenu(Editor.examplesMenu); } public static void selectSerialPort(String port) { diff --git a/build/shared/manpage.adoc b/build/shared/manpage.adoc index 0ee60f654e0..f35e34ce219 100644 --- a/build/shared/manpage.adoc +++ b/build/shared/manpage.adoc @@ -75,6 +75,8 @@ OPTIONS {empty}:: If this option is not passed, the value from the current preferences is used (e.g., the last board selected in the IDE). + If this option is given, the value passed is written to the + preferences file and rememberd for subsequent runs. *--port* __portname__:: Select the serial port to perform upload of the sketch. @@ -85,6 +87,8 @@ OPTIONS {empty}:: If this option is not passed, the value from the current preferences is used (e.g., the last port selected in the IDE). + If this option is given, the value passed is written to the + preferences file and rememberd for subsequent runs. *--verbose-build*:: Enable verbose mode during build. If this option is not given, @@ -108,16 +112,15 @@ OPTIONS *--pref* __name__=__value__:: Sets the preference __name__ to the given __value__. -{empty}:: - Currently the preferences set are saved to 'preferences.txt', but - this might change in the future (making them only active during - the current invocation). - {empty}:: Note that the preferences you set with this option are not validated: Invalid names will be set but never used, invalid values might lead to an error later on. +{empty}:: + If this option is given, the value passed is written to the + preferences file and rememberd for subsequent runs. + *--upload*:: Build and upload the sketch. @@ -237,6 +240,11 @@ HISTORY longer shown. Error messages still use a graphical popup and on Windows, the splash screen is still shown. +1.5.7:: + *--board* and *--port* options are now saved to the preferences + file, just like *--pref*. The *--verbose* options still only + apply to the current run. + RESOURCES --------- Web site: From 07181def1e428f30e5b004c1960e35652ce53c5d Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 11:47:04 +0200 Subject: [PATCH 08/25] Error when passing --verbose without --verify or --upload Since the handling of these options defaults to non-verbose (instead of the current preference), they make no sense when starting the IDE normally. Previously, these options would just be ignored in this case, now an error is shown. --- app/src/processing/app/Base.java | 3 +++ build/shared/manpage.adoc | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index ef70c4a1d8e..ce1fdf2f939 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -401,6 +401,9 @@ public Base(String[] args) throws Exception { if ((action == ACTION.UPLOAD || action == ACTION.VERIFY) && filenames.size() != 1) showError(null, _("Must specify exactly one sketch file"), 3); + if ((action != ACTION.UPLOAD && action != ACTION.VERIFY) && (doVerboseBuild || doVerboseUpload)) + showError(null, _("--verbose, --verbose-upload and --verbose-build can only be used together with --verify or --upload"), 3); + for (String path: filenames) { // Fix a problem with systems that use a non-ASCII languages. Paths are // being passed in with 8.3 syntax, which makes the sketch loader code diff --git a/build/shared/manpage.adoc b/build/shared/manpage.adoc index f35e34ce219..709676b804c 100644 --- a/build/shared/manpage.adoc +++ b/build/shared/manpage.adoc @@ -95,16 +95,28 @@ OPTIONS verbose mode during build is disabled regardless of the current preferences. +{empty}:: + This option is only valid together with *--verify* or + *--upload*. + *--verbose-upload*:: Enable verbose mode during upload. If this option is not given, verbose mode during upload is disabled regardless of the current preferences. +{empty}:: + This option is only valid together with *--verify* or + *--upload*. + *-v, --verbose*:: Enable verbose mode during build and upload. This option has the same effect of using both *--verbose-build* and *--verbose-upload*. +{empty}:: + This option is only valid together with *--verify* or + *--upload*. + *--preferences-file* __filename__:: Read and store preferences from the specified __filename__ instead of the default one. From bdc98a9d5fc1d914c8c4b1ba1709a49ced744730 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 10:38:25 +0200 Subject: [PATCH 09/25] Explicitely save preferences on startup Before, the preferences were saved as a side effect of loading files in the Editor, but it seems better to explicitely save them as well (this should prevent problems later on, if the Editor class is no longer used in --verify or --upload mode). --- app/src/processing/app/Base.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index ce1fdf2f939..885bb74271d 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -433,6 +433,11 @@ public Base(String[] args) throws Exception { } } + // Save the preferences. For GUI mode, this happens in the quit + // handler, but for other modes we should also make sure to save + // them. + Preferences.save(); + switch (action) { case VERIFY: case UPLOAD: From 06416aac68fe2db0666753b4b84293cefd75c29c Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 10:40:45 +0200 Subject: [PATCH 10/25] Add --no-save-prefs option This allows setting preferences for the current run only, without remembering them for the next run. This is especially useful when combined with --verify or --upload. --- app/src/processing/app/Base.java | 4 ++++ app/src/processing/app/Preferences.java | 8 ++++++++ build/shared/manpage.adoc | 15 ++++++++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 885bb74271d..a4b6e13934f 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -385,6 +385,10 @@ public Base(String[] args) throws Exception { processPrefArgument(args[i]); continue; } + if (args[i].equals("--no-save-prefs")) { + Preferences.setDoSave(false); + continue; + } if (args[i].equals("--preferences-file")) { i++; if (i >= args.length) diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 73b980ef52b..1196810865a 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -220,6 +220,7 @@ public String toString() { static Hashtable defaults; static Hashtable table = new Hashtable(); static File preferencesFile; + static boolean doSave = true; static protected void init(String args[]) { @@ -789,6 +790,7 @@ static public String[] loadStrings(InputStream input) { static protected void save() { + if (!doSave) return; // try { // on startup, don't worry about it // this is trying to update the prefs for who is open @@ -989,4 +991,10 @@ static public PreferencesMap getMap() return new PreferencesMap(table); } + // Decide wether changed preferences will be saved. When value is + // false, Preferences.save becomes a no-op. + static public void setDoSave(boolean value) + { + doSave = value; + } } diff --git a/build/shared/manpage.adoc b/build/shared/manpage.adoc index 709676b804c..12d2bdba9a3 100644 --- a/build/shared/manpage.adoc +++ b/build/shared/manpage.adoc @@ -76,7 +76,8 @@ OPTIONS If this option is not passed, the value from the current preferences is used (e.g., the last board selected in the IDE). If this option is given, the value passed is written to the - preferences file and rememberd for subsequent runs. + preferences file and rememberd for subsequent runs (except when + *--no-save-prefs* is passed). *--port* __portname__:: Select the serial port to perform upload of the sketch. @@ -88,7 +89,8 @@ OPTIONS If this option is not passed, the value from the current preferences is used (e.g., the last port selected in the IDE). If this option is given, the value passed is written to the - preferences file and rememberd for subsequent runs. + preferences file and rememberd for subsequent runs (except when + *--no-save-prefs* is passed). *--verbose-build*:: Enable verbose mode during build. If this option is not given, @@ -131,7 +133,11 @@ OPTIONS {empty}:: If this option is given, the value passed is written to the - preferences file and rememberd for subsequent runs. + preferences file and rememberd for subsequent runs (except when + *--no-save-prefs* is passed). + +*--no-save-prefs*:: + Do not save any (changed) preferences to *preferences.txt*. *--upload*:: Build and upload the sketch. @@ -253,6 +259,9 @@ HISTORY Windows, the splash screen is still shown. 1.5.7:: + Introduced *--no-save-prefs*. + +{empty}:: *--board* and *--port* options are now saved to the preferences file, just like *--pref*. The *--verbose* options still only apply to the current run. From 0f18e3d4f4e62de09495032e67d50bd64cdf2d7f Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 11:30:00 +0200 Subject: [PATCH 11/25] Don't save a new preferences file in Preferences.init Preferences.init would write out the default preferences when no preference file previously existed. This would cause a default preferences file to be written even when --no-save-prefs was passed, due to the ordering of things. However, since the Base constructor now already calls Preferences.save(), there is no need for Preferences.init to also do this. Since Base calls this after parsing the commandline, the --no-save-prefs option is now also properly respected. --- app/src/processing/app/Preferences.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 1196810865a..ca390084590 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -266,11 +266,7 @@ static protected void init(String args[]) { } } - if (!preferencesFile.exists()) { - // create a new preferences file if none exists - // saves the defaults out to the file - save(); - } else { + if (preferencesFile.exists()) { // load the previous preferences file try { load(new FileInputStream(preferencesFile)); From c3440175c70edc9278e40eaf7181c657a7356b28 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 11:51:09 +0200 Subject: [PATCH 12/25] Ensure --verbose is never saved to preferences.txt Previously, --verbose would be processed after the preferences were saved, which should usually mean that it should never influence the saved preferences. However, if for whatever reason Preferences.save() would be called later, the verbosity preferences would still be messed up. Since we now have a Preferences.setDoSave() method, we can make sure that these verbosity preferences (and any other preferences that are changed after the build started) are never saved. --- app/src/processing/app/Base.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index a4b6e13934f..b60e9a1ea10 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -449,6 +449,10 @@ public Base(String[] args) throws Exception { Preferences.set("build.verbose", "" + doVerboseBuild); Preferences.set("upload.verbose", "" + doVerboseUpload); + // Make sure these verbosity preferences are only for the + // current session + Preferences.setDoSave(false); + Editor editor = editors.get(0); if (action == ACTION.UPLOAD) { From c27880fe54092e6f0b35f71da9b677a5d7e3fecd Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 12:01:54 +0200 Subject: [PATCH 13/25] Add --noop option This option causes the IDE to process its commandline arguments and then quit. This allows setting preferences uses --pref, without having to also load the GUI or compile a sketch. --- app/src/processing/app/Base.java | 10 +++++++++- build/shared/manpage.adoc | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index b60e9a1ea10..475757f44e5 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -268,7 +268,7 @@ static protected void initRequirements() { } - protected static enum ACTION { GUI, VERIFY, UPLOAD }; + protected static enum ACTION { GUI, VERIFY, UPLOAD, NOOP }; public Base(String[] args) throws Exception { platform.init(this); @@ -331,6 +331,7 @@ public Base(String[] args) throws Exception { final Map actions = new HashMap(); actions.put("--verify", ACTION.VERIFY); actions.put("--upload", ACTION.UPLOAD); + actions.put("--noop", ACTION.NOOP); // Check if any files were passed in on the command line for (int i = 0; i < args.length; i++) { @@ -405,6 +406,9 @@ public Base(String[] args) throws Exception { if ((action == ACTION.UPLOAD || action == ACTION.VERIFY) && filenames.size() != 1) showError(null, _("Must specify exactly one sketch file"), 3); + if (action == ACTION.NOOP && filenames.size() != 0) + showError(null, _("Cannot specify any sketch files"), 3); + if ((action != ACTION.UPLOAD && action != ACTION.VERIFY) && (doVerboseBuild || doVerboseUpload)) showError(null, _("--verbose, --verbose-upload and --verbose-build can only be used together with --verify or --upload"), 3); @@ -485,6 +489,10 @@ public Base(String[] args) throws Exception { new UpdateCheck(this); } break; + case NOOP: + // Do nothing (intended for only changing preferences) + System.exit(0); + break; } } diff --git a/build/shared/manpage.adoc b/build/shared/manpage.adoc index 12d2bdba9a3..db52b2f5038 100644 --- a/build/shared/manpage.adoc +++ b/build/shared/manpage.adoc @@ -145,6 +145,10 @@ OPTIONS *--verify*:: Build the sketch. +*--noop*:: + Immediately quit after processing the commandline. This can be + used to just set preferences with *--pref*. + PREFERENCES ----------- Arduino keeps a list of preferences, as simple name and value pairs. @@ -232,6 +236,10 @@ re-use any previous build results in that directory. arduino --pref build.path=/path/to/sketch/build --verify /path/to/sketch/sketch.ino +Change the selected board and build path and do nothing else. + + arduino --pref build.path=/path/to/sketch/build --board arduino:avr:uno --noop + HISTORY ------- 1.5.2:: @@ -259,7 +267,7 @@ HISTORY Windows, the splash screen is still shown. 1.5.7:: - Introduced *--no-save-prefs*. + Introduced *--no-save-prefs* and *--noop*. {empty}:: *--board* and *--port* options are now saved to the preferences From 6e8eaffce7c7d16ba7bbbd9aaa5df69464d63053 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 7 Apr 2014 12:19:22 +0200 Subject: [PATCH 14/25] Add --get-pref option This allows reading specific preferences from the commandline. --- app/src/processing/app/Base.java | 21 +++++++++++++++++++-- build/shared/manpage.adoc | 6 ++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 475757f44e5..970135d9817 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -268,7 +268,7 @@ static protected void initRequirements() { } - protected static enum ACTION { GUI, VERIFY, UPLOAD, NOOP }; + protected static enum ACTION { GUI, VERIFY, UPLOAD, NOOP, GET_PREF }; public Base(String[] args) throws Exception { platform.init(this); @@ -322,6 +322,7 @@ public Base(String[] args) throws Exception { ACTION action = ACTION.GUI; boolean doVerboseBuild = false; boolean doVerboseUpload = false;; + String getPref = null; String selectBoard = null; String selectPort = null; String currentDirectory = System.getProperty("user.dir"); @@ -332,6 +333,7 @@ public Base(String[] args) throws Exception { actions.put("--verify", ACTION.VERIFY); actions.put("--upload", ACTION.UPLOAD); actions.put("--noop", ACTION.NOOP); + actions.put("--get-pref", ACTION.GET_PREF); // Check if any files were passed in on the command line for (int i = 0; i < args.length; i++) { @@ -342,6 +344,12 @@ public Base(String[] args) throws Exception { String mess = I18n.format(_("Can only pass one of: {0}"), PApplet.join(valid, ", ")); showError(null, mess, 3); } + if (a == ACTION.GET_PREF) { + i++; + if (i >= args.length) + showError(null, _("Argument required for --get-pref"), 3); + getPref = args[i]; + } action = a; continue; } @@ -406,7 +414,7 @@ public Base(String[] args) throws Exception { if ((action == ACTION.UPLOAD || action == ACTION.VERIFY) && filenames.size() != 1) showError(null, _("Must specify exactly one sketch file"), 3); - if (action == ACTION.NOOP && filenames.size() != 0) + if ((action == ACTION.NOOP || action == ACTION.GET_PREF) && filenames.size() != 0) showError(null, _("Cannot specify any sketch files"), 3); if ((action != ACTION.UPLOAD && action != ACTION.VERIFY) && (doVerboseBuild || doVerboseUpload)) @@ -493,6 +501,15 @@ public Base(String[] args) throws Exception { // Do nothing (intended for only changing preferences) System.exit(0); break; + case GET_PREF: + String value = Preferences.get(getPref, null); + if (value != null) { + System.out.println(value); + System.exit(0); + } else { + System.exit(4); + } + break; } } diff --git a/build/shared/manpage.adoc b/build/shared/manpage.adoc index db52b2f5038..46a0b49462f 100644 --- a/build/shared/manpage.adoc +++ b/build/shared/manpage.adoc @@ -149,6 +149,11 @@ OPTIONS Immediately quit after processing the commandline. This can be used to just set preferences with *--pref*. +*--get-pref __preference__*:: + Prints the value of the given preference to the standard output + stream. When the value does not exist, nothing is printed and + the exit status is set (see EXIT STATUS below). + PREFERENCES ----------- Arduino keeps a list of preferences, as simple name and value pairs. @@ -185,6 +190,7 @@ EXIT STATUS *1*:: Build failed or upload failed *2*:: Sketch not found *3*:: Invalid (argument for) commandline option +*4*:: Preference passed to *--get-pref* does not exist FILES ----- From 95e33f6f2497e4457d99002525c2f8abbb6ec368 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 8 Apr 2014 11:19:58 +0200 Subject: [PATCH 15/25] Parse --preferences-file in main instead of Preferences.init Parsing commandline arguments inside Preferences isn't very elegant, this is better suited for the main function. Also, this change prepares for taking --curdir into account for --preferences-file as well. --- app/src/processing/app/Base.java | 16 ++++++++++++++-- app/src/processing/app/Preferences.java | 17 +++++------------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 970135d9817..c612e2e8301 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -139,8 +139,20 @@ static public void main(String args[]) throws Exception { if (!portableFolder.exists()) portableFolder = null; + File preferencesFile = null; + + // Do a first pass over the commandline arguments, the rest of them + // will be processed by the Base constructor. Note that this loop + // does not look at the last element of args, to prevent crashing + // when no parameter was specified to an option. Later, Base() will + // then show an error for these. + for (int i = 0; i < args.length - 1; i++) { + if (args[i].equals("--preferences-file")) + preferencesFile = new File(args[i + 1]); + } + // run static initialization that grabs all the prefs - Preferences.init(args); + Preferences.init(preferencesFile); try { File versionFile = getContentFile("lib/version.txt"); @@ -402,7 +414,7 @@ public Base(String[] args) throws Exception { i++; if (i >= args.length) showError(null, _("Argument required for --preferences-file"), 3); - // Argument should be already processed by Preferences.init(...) + // Argument should be already processed by Base.main(...) continue; } if (args[i].startsWith("--")) diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index ca390084590..3e0d564ebcd 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -223,7 +223,11 @@ public String toString() { static boolean doSave = true; - static protected void init(String args[]) { + static protected void init(File file) { + if (file != null) + preferencesFile = file; + else + preferencesFile = Base.getSettingsFile(Preferences.PREFS_FILE); // start by loading the defaults, in case something // important was deleted from the user prefs @@ -255,17 +259,6 @@ static protected void init(String args[]) { // clone the hash table defaults = new Hashtable(table); - // next load user preferences file - preferencesFile = Base.getSettingsFile(PREFS_FILE); - - // load a preferences file if specified on the command line - if (args != null) { - for (int i = 0; i < args.length - 1; i++) { - if (args[i].equals("--preferences-file")) - preferencesFile = new File(args[i + 1]); - } - } - if (preferencesFile.exists()) { // load the previous preferences file try { From e10ecad98b6752f1fe0515d4f39f6ad8485f527d Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 8 Apr 2014 12:07:20 +0200 Subject: [PATCH 16/25] Don't re-parse arguments to --preferences-file Previously, the argument to --preferences-file would be interpreted as a filename, but then also checked as an option as well (in the next loop iteration). This didn't really matter in practice (unless you would be using a file called "--preferences-file"), but better skip the argument anyway. --- app/src/processing/app/Base.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index c612e2e8301..92768787c53 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -147,8 +147,10 @@ static public void main(String args[]) throws Exception { // when no parameter was specified to an option. Later, Base() will // then show an error for these. for (int i = 0; i < args.length - 1; i++) { - if (args[i].equals("--preferences-file")) - preferencesFile = new File(args[i + 1]); + if (args[i].equals("--preferences-file")) { + ++i; + preferencesFile = new File(args[i]); + } } // run static initialization that grabs all the prefs From 9249c78baf405d1e3a9bd6b45c8e4be10dd993c0 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 8 Apr 2014 12:11:08 +0200 Subject: [PATCH 17/25] Parse --curdir in Base.main() This shouldn't change any behaviour, but prepares for upcoming changes. --- app/src/processing/app/Base.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 92768787c53..2eb5a75cf9b 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -117,6 +117,10 @@ public class Base { // Location for untitled items static File untitledFolder; + // Current directory to use for relative paths specified on the + // commandline + static String currentDirectory = System.getProperty("user.dir"); + // p5 icon for the window // static Image icon; @@ -150,6 +154,12 @@ static public void main(String args[]) throws Exception { if (args[i].equals("--preferences-file")) { ++i; preferencesFile = new File(args[i]); + continue; + } + if (args[i].equals("--curdir")) { + i++; + currentDirectory = args[i]; + continue; } } @@ -339,7 +349,6 @@ public Base(String[] args) throws Exception { String getPref = null; String selectBoard = null; String selectPort = null; - String currentDirectory = System.getProperty("user.dir"); List filenames = new LinkedList(); // Map of possible actions and corresponding options @@ -398,7 +407,7 @@ public Base(String[] args) throws Exception { i++; if (i >= args.length) showError(null, _("Argument required for --curdir"), 3); - currentDirectory = args[i]; + // Argument should be already processed by Base.main(...) continue; } if (args[i].equals("--pref")) { From a087c8e572f694f9fc18c7a7f5b511ba1b4b24bb Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 8 Apr 2014 12:35:22 +0200 Subject: [PATCH 18/25] Pass around sketch File objects instead of filenames This saves a few conversions from File object to String and is generally cleaner. --- app/src/processing/app/Base.java | 45 ++++++++++--------- app/src/processing/app/Editor.java | 26 +++++------ app/src/processing/app/Sketch.java | 11 +++-- .../processing/app/macosx/ThinkDifferent.java | 4 +- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 2eb5a75cf9b..ba7a1f0364c 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -462,7 +462,7 @@ public Base(String[] args) throws Exception { } boolean showEditor = (action == ACTION.GUI); - if (handleOpen(path, nextEditorLocation(), showEditor) == null) { + if (handleOpen(new File(path), nextEditorLocation(), showEditor) == null) { String mess = I18n.format(_("Failed to open sketch: \"{0}\""), path); // Open failure is fatal in upload/verify mode if (action == ACTION.VERIFY || action == ACTION.UPLOAD) @@ -654,7 +654,7 @@ protected boolean restoreSketches() throws Exception { location = nextEditorLocation(); } // If file did not exist, null will be returned for the Editor - if (handleOpen(path, location, true) != null) { + if (handleOpen(new File(path), location, true) != null) { opened++; } } @@ -812,7 +812,7 @@ protected int[] nextEditorLocation() { * @param shift whether shift is pressed, which will invert prompt setting * @param noPrompt disable prompt, no matter the setting */ - protected String createNewUntitled() throws IOException { + protected File createNewUntitled() throws IOException { File newbieDir = null; String newbieName = null; @@ -859,7 +859,7 @@ protected String createNewUntitled() throws IOException { throw new IOException(); } FileUtils.copyFile(new File(getContentFile("examples"), "01.Basics" + File.separator + "BareMinimum" + File.separator + "BareMinimum.ino"), newbieFile); - return newbieFile.getAbsolutePath(); + return newbieFile; } @@ -869,9 +869,9 @@ protected String createNewUntitled() throws IOException { */ public void handleNew() throws Exception { try { - String path = createNewUntitled(); - if (path != null) { - Editor editor = handleOpen(path); + File file = createNewUntitled(); + if (file != null) { + Editor editor = handleOpen(file); editor.untitled = true; } @@ -900,9 +900,9 @@ public void handleNewReplace() { protected void handleNewReplaceImpl() { try { - String path = createNewUntitled(); - if (path != null) { - activeEditor.handleOpenInternal(path); + File file = createNewUntitled(); + if (file != null) { + activeEditor.handleOpenInternal(file); activeEditor.untitled = true; } // return true; @@ -918,14 +918,14 @@ protected void handleNewReplaceImpl() { * Open a sketch, replacing the sketch in the current window. * @param path Location of the primary pde file for the sketch. */ - public void handleOpenReplace(String path) { + public void handleOpenReplace(File file) { if (!activeEditor.checkModified()) { return; // sketch was modified, and user canceled } // Close the running window, avoid window boogers with multiple sketches activeEditor.internalCloseRunner(); - boolean loaded = activeEditor.handleOpenInternal(path); + boolean loaded = activeEditor.handleOpenInternal(file); if (!loaded) { // replace the document without checking if that's ok handleNewReplaceImpl(); @@ -956,30 +956,30 @@ public void handleOpenPrompt() throws Exception { File inputFile = fd.getSelectedFile(); Preferences.set("last.folder", inputFile.getAbsolutePath()); - handleOpen(inputFile.getAbsolutePath()); + handleOpen(inputFile); } /** * Open a sketch in a new window. - * @param path Path to the pde file for the sketch in question + * @param file File to open * @return the Editor object, so that properties (like 'untitled') * can be set by the caller * @throws Exception */ - public Editor handleOpen(String path) throws Exception { - return handleOpen(path, nextEditorLocation(), true); + public Editor handleOpen(File file) throws Exception { + return handleOpen(file, nextEditorLocation(), true); } - protected Editor handleOpen(String path, int[] location, boolean showEditor) throws Exception { + protected Editor handleOpen(File file, int[] location, boolean showEditor) throws Exception { // System.err.println("entering handleOpen " + path); - File file = new File(path); if (!file.exists()) return null; // System.err.println(" editors: " + editors); // Cycle through open windows to make sure that it's not already open. + String path = file.getAbsolutePath(); for (Editor editor : editors) { if (editor.getSketch().getMainFilePath().equals(path)) { editor.toFront(); @@ -1003,7 +1003,7 @@ protected Editor handleOpen(String path, int[] location, boolean showEditor) thr // } // System.err.println(" creating new editor"); - Editor editor = new Editor(this, path, location); + Editor editor = new Editor(this, file, location); // Editor editor = null; // try { // editor = new Editor(this, path, location); @@ -1746,16 +1746,17 @@ private boolean addSketchesSubmenu(JMenu menu, String name, File folder, ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { String path = e.getActionCommand(); - if (new File(path).exists()) { + File file = new File(path); + if (file.exists()) { boolean replace = replaceExisting; if ((e.getModifiers() & ActionEvent.SHIFT_MASK) != 0) { replace = !replace; } if (replace) { - handleOpenReplace(path); + handleOpenReplace(file); } else { try { - handleOpen(path); + handleOpen(file); } catch (Exception e1) { e1.printStackTrace(); } diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 9fa785e7090..5519d30f452 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -155,7 +155,7 @@ public class Editor extends JFrame implements RunnerListener { Runnable exportAppHandler; - public Editor(Base ibase, String path, int[] location) throws Exception { + public Editor(Base ibase, File file, int[] location) throws Exception { super("Arduino"); this.base = ibase; @@ -310,7 +310,7 @@ public void windowDeactivated(WindowEvent e) { // System.out.println("t4"); // Open the document that was passed in - boolean loaded = handleOpenInternal(path); + boolean loaded = handleOpenInternal(file); if (!loaded) sketch = null; // System.out.println("t5"); @@ -2092,10 +2092,10 @@ protected boolean checkModified() { * Open a sketch from a particular path, but don't check to save changes. * Used by Sketch.saveAs() to re-open a sketch after the "Save As" */ - protected void handleOpenUnchecked(String path, int codeIndex, + protected void handleOpenUnchecked(File file, int codeIndex, int selStart, int selStop, int scrollPos) { internalCloseRunner(); - handleOpenInternal(path); + handleOpenInternal(file); // Replacing a document that may be untitled. If this is an actual // untitled document, then editor.untitled will be set by Base. untitled = false; @@ -2110,10 +2110,9 @@ protected void handleOpenUnchecked(String path, int codeIndex, * Second stage of open, occurs after having checked to see if the * modifications (if any) to the previous sketch need to be saved. */ - protected boolean handleOpenInternal(String path) { + protected boolean handleOpenInternal(File file) { // check to make sure that this .pde file is // in a folder of the same name - File file = new File(path); String fileName = file.getName(); File parent = file.getParentFile(); String parentName = parent.getName(); @@ -2127,10 +2126,10 @@ protected boolean handleOpenInternal(String path) { } else if (altPdeFile.exists()) { // user selected a .java from the same sketch, but open the .pde instead - path = altPdeFile.getAbsolutePath(); + file = altPdeFile; } else if (altInoFile.exists()) { - path = altInoFile.getAbsolutePath(); - } else if (!path.endsWith(".ino") && !path.endsWith(".pde")) { + file = altInoFile; + } else if (!fileName.endsWith(".ino") && !fileName.endsWith(".pde")) { Base.showWarning(_("Bad file selected"), _("Processing can only open its own sketches\n" + "and other files ending in .ino or .pde"), null); @@ -2179,19 +2178,18 @@ protected boolean handleOpenInternal(String path) { } // copy the sketch inside File properPdeFile = new File(properFolder, file.getName()); - File origPdeFile = new File(path); try { - Base.copyFile(origPdeFile, properPdeFile); + Base.copyFile(file, properPdeFile); } catch (IOException e) { Base.showWarning(_("Error"), _("Could not copy to a proper location."), e); return false; } // remove the original file, so user doesn't get confused - origPdeFile.delete(); + file.delete(); // update with the new path - path = properPdeFile.getAbsolutePath(); + file = properPdeFile; } else if (result == JOptionPane.NO_OPTION) { return false; @@ -2199,7 +2197,7 @@ protected boolean handleOpenInternal(String path) { } try { - sketch = new Sketch(this, path); + sketch = new Sketch(this, file); } catch (IOException e) { Base.showWarning(_("Error"), _("Could not create the sketch."), e); return false; diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 9d7bbbbc2b1..253af52382d 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -106,10 +106,10 @@ public class Sketch { * path is location of the main .pde file, because this is also * simplest to use when opening the file from the finder/explorer. */ - public Sketch(Editor editor, String path) throws IOException { + public Sketch(Editor editor, File file) throws IOException { this.editor = editor; - primaryFile = new File(path); + primaryFile = file; // get the name of the sketch by chopping .pde or .java // off of the main file name @@ -136,7 +136,7 @@ public Sketch(Editor editor, String path) throws IOException { tempBuildFolder = Base.getBuildFolder(); //Base.addBuildFolderToClassPath(); - folder = new File(new File(path).getParent()); + folder = new File(file.getParent()); //System.out.println("sketch dir is " + folder); load(); @@ -516,12 +516,11 @@ protected void nameCode(String newName) { // if successful, set base properties for the sketch File newMainFile = new File(newFolder, newName + ".ino"); - String newMainFilePath = newMainFile.getAbsolutePath(); // having saved everything and renamed the folder and the main .pde, // use the editor to re-open the sketch to re-init state // (unfortunately this will kill positions for carets etc) - editor.handleOpenUnchecked(newMainFilePath, + editor.handleOpenUnchecked(newMainFile, currentIndex, editor.getSelectionStart(), editor.getSelectionStop(), @@ -915,7 +914,7 @@ protected boolean saveAs() throws IOException { File newFile = new File(newFolder, newName + ".ino"); code[0].saveAs(newFile); - editor.handleOpenUnchecked(newFile.getPath(), + editor.handleOpenUnchecked(newFile, currentIndex, editor.getSelectionStart(), editor.getSelectionStop(), diff --git a/app/src/processing/app/macosx/ThinkDifferent.java b/app/src/processing/app/macosx/ThinkDifferent.java index 6448b1e9aab..0f226dd716a 100644 --- a/app/src/processing/app/macosx/ThinkDifferent.java +++ b/app/src/processing/app/macosx/ThinkDifferent.java @@ -26,6 +26,8 @@ import com.apple.eawt.*; +import java.io.File; + /** * Deal with issues related to thinking different. This handles the basic @@ -97,7 +99,7 @@ public void handleOpenFile(ApplicationEvent ae) { // System.out.println("got open file event " + ae.getFilename()); String filename = ae.getFilename(); try { - base.handleOpen(filename); + base.handleOpen(new File(filename)); } catch (Exception e) { e.printStackTrace(); } From 0ee6d242b244258ea2b9b3f455b9b4dc43062db4 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 8 Apr 2014 12:39:17 +0200 Subject: [PATCH 19/25] Add Base.absoluteFile method This method takes filenames as specified on the commandline and turns them into the right File object, taking into account the current directory passed through --curdir by the wrapper script. --- app/src/processing/app/Base.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index ba7a1f0364c..b7c5d8633d0 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -291,6 +291,18 @@ static protected void initRequirements() { } } + // Returns a File object for the given pathname. If the pathname + // is not absolute, it is interpreted relative to the current + // directory when starting the IDE (which is not the same as the + // current working directory!). + static public File absoluteFile(String path) { + File file = new File(path); + if (!file.isAbsolute()) { + file = new File(currentDirectory, path); + } + return file; + } + protected static enum ACTION { GUI, VERIFY, UPLOAD, NOOP, GET_PREF }; public Base(String[] args) throws Exception { @@ -457,12 +469,11 @@ public Base(String[] args) throws Exception { } } - if (!new File(path).isAbsolute()) { - path = new File(currentDirectory, path).getAbsolutePath(); - } + // Correctly resolve relative paths + File file = absoluteFile(path); boolean showEditor = (action == ACTION.GUI); - if (handleOpen(new File(path), nextEditorLocation(), showEditor) == null) { + if (handleOpen(file, nextEditorLocation(), showEditor) == null) { String mess = I18n.format(_("Failed to open sketch: \"{0}\""), path); // Open failure is fatal in upload/verify mode if (action == ACTION.VERIFY || action == ACTION.UPLOAD) From d0a2e94169efae2d3711d2c12d6a1b488edfd77f Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 8 Apr 2014 12:41:38 +0200 Subject: [PATCH 20/25] Fix --curdir on Windows On Windows, files are canonicalized to prevent issues with legacy 8.3 filenames. However, this canonicalization includes making the path absolute and this happened before applying --curdir to the path, making the latter a noop. By reversing the operations, this should allow both of them to do their work. --- app/src/processing/app/Base.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index b7c5d8633d0..e17feee2c8e 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -456,22 +456,21 @@ public Base(String[] args) throws Exception { showError(null, _("--verbose, --verbose-upload and --verbose-build can only be used together with --verify or --upload"), 3); for (String path: filenames) { + // Correctly resolve relative paths + File file = absoluteFile(path); + // Fix a problem with systems that use a non-ASCII languages. Paths are // being passed in with 8.3 syntax, which makes the sketch loader code // unhappy, since the sketch folder naming doesn't match up correctly. // http://dev.processing.org/bugs/show_bug.cgi?id=1089 if (isWindows()) { try { - File file = new File(path); - path = file.getCanonicalPath(); + file = file.getCanonicalFile(); } catch (IOException e) { e.printStackTrace(); } } - // Correctly resolve relative paths - File file = absoluteFile(path); - boolean showEditor = (action == ACTION.GUI); if (handleOpen(file, nextEditorLocation(), showEditor) == null) { String mess = I18n.format(_("Failed to open sketch: \"{0}\""), path); From 6d54a0694aa5bead9b51780bb8a51c8fd80da373 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 8 Apr 2014 12:54:17 +0200 Subject: [PATCH 21/25] Fix opening a non-primary .ino file When a sketch looks like this: Blink/ Blink.ino Foo.ino The idea is that opening Foo.ino should open up the sketch. However, before this would show an error stating "The file Foo.ino needs to be inside a sketch folder named Foo" instead. This turned out to be due to a typo, which seems to have been present for a long time. Note that when the main sketch file was a .pde file, everything already worked as expected. --- app/src/processing/app/Editor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 5519d30f452..78b96d270ea 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -2119,7 +2119,7 @@ protected boolean handleOpenInternal(File file) { String pdeName = parentName + ".pde"; File altPdeFile = new File(parent, pdeName); String inoName = parentName + ".ino"; - File altInoFile = new File(parent, pdeName); + File altInoFile = new File(parent, inoName); if (pdeName.equals(fileName) || inoName.equals(fileName)) { // no beef with this guy From d582b73df8e52cee4ca02d5e0142b0a3fb10d971 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 9 Apr 2014 22:33:53 +0200 Subject: [PATCH 22/25] Take into account --curdir for all relative paths In a lot of places, (potentially) relative paths were passed to File without any processing, making them be resolved without taking into account --curdir. By passing them through Base.absoluteFile instead, these paths are resolved relative to the working directory before starting arduino (at least on Linux, which is currently the only platform supporting --curdir). This applies --curdir to the --preferences-file option and the build.path, settings.path, sketchbook.path preferences. For example, this now works as expected: arduino --pref build.path=build_dir --verify Blink.ino --- app/src/processing/app/Base.java | 17 +++++++++-------- build/shared/manpage.adoc | 7 +++++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index e17feee2c8e..a511f24450a 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -143,7 +143,7 @@ static public void main(String args[]) throws Exception { if (!portableFolder.exists()) portableFolder = null; - File preferencesFile = null; + String preferencesFile = null; // Do a first pass over the commandline arguments, the rest of them // will be processed by the Base constructor. Note that this loop @@ -153,7 +153,7 @@ static public void main(String args[]) throws Exception { for (int i = 0; i < args.length - 1; i++) { if (args[i].equals("--preferences-file")) { ++i; - preferencesFile = new File(args[i]); + preferencesFile = args[i]; continue; } if (args[i].equals("--curdir")) { @@ -164,7 +164,7 @@ static public void main(String args[]) throws Exception { } // run static initialization that grabs all the prefs - Preferences.init(preferencesFile); + Preferences.init(absoluteFile(preferencesFile)); try { File versionFile = getContentFile("lib/version.txt"); @@ -296,6 +296,8 @@ static protected void initRequirements() { // directory when starting the IDE (which is not the same as the // current working directory!). static public File absoluteFile(String path) { + if (path == null) return null; + File file = new File(path); if (!file.isAbsolute()) { file = new File(currentDirectory, path); @@ -320,7 +322,7 @@ public Base(String[] args) throws Exception { if (portableFolder != null) sketchbookFolder = new File(portableFolder, sketchbookPath); else - sketchbookFolder = new File(sketchbookPath); + sketchbookFolder = Base.absoluteFile(sketchbookPath); if (!sketchbookFolder.exists()) { Base.showWarning(_("Sketchbook folder disappeared"), _("The sketchbook folder no longer exists.\n" + @@ -2047,7 +2049,7 @@ static public File getSettingsFolder() { String preferencesPath = Preferences.get("settings.path"); if (preferencesPath != null) { - settingsFolder = new File(preferencesPath); + settingsFolder = absoluteFile(preferencesPath); } else { try { @@ -2086,8 +2088,7 @@ static public File getBuildFolder() { if (buildFolder == null) { String buildPath = Preferences.get("build.path"); if (buildPath != null) { - buildFolder = new File(buildPath); - + buildFolder = Base.absoluteFile(buildPath); } else { //File folder = new File(getTempFolder(), "build"); //if (!folder.exists()) folder.mkdirs(); @@ -2248,7 +2249,7 @@ static public String getPortableSketchbookFolder() { static public File getSketchbookFolder() { if (portableFolder != null) return new File(portableFolder, Preferences.get("sketchbook.path")); - return new File(Preferences.get("sketchbook.path")); + return absoluteFile(Preferences.get("sketchbook.path")); } diff --git a/build/shared/manpage.adoc b/build/shared/manpage.adoc index 46a0b49462f..7af5a8c7ccf 100644 --- a/build/shared/manpage.adoc +++ b/build/shared/manpage.adoc @@ -280,6 +280,13 @@ HISTORY file, just like *--pref*. The *--verbose* options still only apply to the current run. +{empty}:: + A path passed to *--preferences-file*, or set in the + *build.path*, *preferences.path* or *settings.path* is now + interpreted relative to the current directory instead of the + location of the arduino command itself. + + RESOURCES --------- Web site: From c84edbc0ef646db9d27355015ca1342f71d0226e Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 5 Dec 2013 19:59:54 +0100 Subject: [PATCH 23/25] Let Editor::statusError print to stderr Before, these were only shown in the GUI, which makes a failing commandline build a bit puzzling. As a side effect, the error is now shown in the log area in addition to the status line above the log area, but that should be ok. --- app/src/processing/app/Editor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 78b96d270ea..e8b3c170cc6 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -2637,6 +2637,7 @@ public void handlePrint() { * Show an error int the status bar. */ public void statusError(String what) { + System.err.println(what); status.error(what); //new Exception("deactivating RUN").printStackTrace(); toolbar.deactivate(EditorToolbar.RUN); From ae19b7bd3d1d3df12b1ada2c663a8233371cb88a Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 9 Apr 2014 21:56:55 +0200 Subject: [PATCH 24/25] If build.path is specified, create it if needed When no build.path preference is present, a temporary directory is automatically created (and deleted). When a build.path was specified, but the directory does not exist, the IDE would show an error and fail to build, which is unexpected and not so friendly. This commit makes sure that the build directory is automatically created. --- app/src/processing/app/Base.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index a511f24450a..2be9664e278 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2089,6 +2089,8 @@ static public File getBuildFolder() { String buildPath = Preferences.get("build.path"); if (buildPath != null) { buildFolder = Base.absoluteFile(buildPath); + if (!buildFolder.exists()) + buildFolder.mkdirs(); } else { //File folder = new File(getTempFolder(), "build"); //if (!folder.exists()) folder.mkdirs(); From 7f23924dd53185ead67d3c8f6143d4e9220da1c7 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 10 Apr 2014 12:34:52 +0200 Subject: [PATCH 25/25] Fix preference directory opening in the GUI with --preferences-file In the preferences dialog, the name of the preferences file is shown for advanced editing. If the filename is clicked, the folder containing the file is opened. However, this always used Base.getSettingsFolder, which is the folder where the settings file _normally_ resides. But when the --preferences-file option is used, the actual preferences file might be somewhere else. This commit makes sure to always open up the parent directory of the actual preferences file in use, instead of always the default one. --- app/src/processing/app/Preferences.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 3e0d564ebcd..dc2b04b99fa 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -492,7 +492,7 @@ public void actionPerformed(ActionEvent e) { final JLabel clickable = label; label.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { - Base.openFolder(Base.getSettingsFolder()); + Base.openFolder(preferencesFile.getParentFile()); } public void mouseEntered(MouseEvent e) {