Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux: Removed X11 requirement when running in command line mode #5578

Merged
merged 13 commits into from Nov 25, 2016
Merged
8 changes: 6 additions & 2 deletions app/src/cc/arduino/view/SplashScreenHelper.java
Expand Up @@ -51,8 +51,12 @@ public class SplashScreenHelper {

public SplashScreenHelper(SplashScreen splash) {
this.splash = splash;
Toolkit tk = Toolkit.getDefaultToolkit();
desktopHints = (Map) tk.getDesktopProperty("awt.font.desktophints");
if (splash != null) {
Toolkit tk = Toolkit.getDefaultToolkit();
desktopHints = (Map) tk.getDesktopProperty("awt.font.desktophints");
} else {
desktopHints = null;
}
}

public void splashText(String text) {
Expand Down
256 changes: 141 additions & 115 deletions app/src/processing/app/Base.java
Expand Up @@ -22,8 +22,10 @@

package processing.app;

import cc.arduino.Compiler;
import cc.arduino.Constants;
import cc.arduino.UpdatableBoardsLibsFakeURLsHandler;
import cc.arduino.UploaderUtils;
import cc.arduino.contributions.*;
import cc.arduino.contributions.libraries.*;
import cc.arduino.contributions.libraries.ui.LibraryManagerUI;
Expand Down Expand Up @@ -84,7 +86,6 @@ public class Base {
private static boolean commandLine;
public static volatile Base INSTANCE;

public static SplashScreenHelper splashScreenHelper = new SplashScreenHelper(SplashScreen.getSplashScreen());
public static Map<String, Object> FIND_DIALOG_STATE = new HashMap<>();
private final ContributionInstaller contributionInstaller;
private final LibraryInstaller libraryInstaller;
Expand Down Expand Up @@ -128,59 +129,13 @@ static public void main(String args[]) throws Exception {
}

try {
guardedMain(args);
INSTANCE = new Base(args);
} catch (Throwable e) {
e.printStackTrace(System.err);
System.exit(255);
}
}

static public void guardedMain(String args[]) throws Exception {
Thread deleteFilesOnShutdownThread = new Thread(DeleteFilesOnShutdown.INSTANCE);
deleteFilesOnShutdownThread.setName("DeleteFilesOnShutdown");
Runtime.getRuntime().addShutdownHook(deleteFilesOnShutdownThread);

BaseNoGui.initLogger();

initLogger();

BaseNoGui.initPlatform();

BaseNoGui.getPlatform().init();

BaseNoGui.initPortableFolder();

BaseNoGui.initParameters(args);

splashScreenHelper.splashText(tr("Loading configuration..."));

BaseNoGui.initVersion();

// Use native popups so they don't look so crappy on osx
JPopupMenu.setDefaultLightWeightPopupEnabled(false);

// Don't put anything above this line that might make GUI,
// because the platform has to be inited properly first.

// setup the theme coloring fun
Theme.init();
System.setProperty("swing.aatext", PreferencesData.get("editor.antialias", "true"));

// Set the look and feel before opening the window
try {
BaseNoGui.getPlatform().setLookAndFeel();
} catch (Exception e) {
// ignore
}

// Create a location for untitled sketches
untitledFolder = FileUtils.createTempFolder("untitled" + new Random().nextInt(Integer.MAX_VALUE), ".tmp");
DeleteFilesOnShutdown.add(untitledFolder);

INSTANCE = new Base(args);
}


static public void initLogger() {
Handler consoleHandler = new ConsoleLogger();
consoleHandler.setLevel(Level.ALL);
Expand Down Expand Up @@ -208,12 +163,6 @@ static public void initLogger() {

}


static protected void setCommandLine() {
commandLine = true;
}


static protected boolean isCommandLine() {
return commandLine;
}
Expand All @@ -227,10 +176,60 @@ static public File absoluteFile(String path) {
}

public Base(String[] args) throws Exception {
BaseNoGui.notifier = new GUIUserNotifier(this);
Thread deleteFilesOnShutdownThread = new Thread(DeleteFilesOnShutdown.INSTANCE);
deleteFilesOnShutdownThread.setName("DeleteFilesOnShutdown");
Runtime.getRuntime().addShutdownHook(deleteFilesOnShutdownThread);

BaseNoGui.initLogger();

initLogger();

BaseNoGui.initPlatform();

BaseNoGui.getPlatform().init();

BaseNoGui.initPortableFolder();

// Look for a possible "--preferences-file" parameter and load preferences
BaseNoGui.initParameters(args);

CommandlineParser parser = new CommandlineParser(args);
parser.parseArgumentsPhase1();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now parseArgumentsPhase1 is moved up this far, it might be good to move it even further up so BaseNoGui.initParameters can just use the --preferences-file value as parsed by parser, instead of having to parse it iself. From a quick glance of parseArgumentsPhase1, it seems this does not depend on the preferences file being loaded? This should probably be a different commit, of course.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately parseArgumentsPhase1 depends on preferences being loaded, it uses PreferencesData in 3 or 4 places. Of course this smells like a bad design, the CommandLineParser class should only parse the command line and actions should be taken outside. I guess it's the result of trying to keep low the amount of changes involved in previous refactorings.

(again, while doing this PR I tried also to fix this one, but dropped this task to focus on solving the X11 issue)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Sounds like the commandline parsing needs another refactor after this one then (or, at least a parseArgumentsPhase0 to just parse the preferences path).

commandLine = !parser.isGuiMode();

SplashScreenHelper splash;
if (parser.isGuiMode()) {
// Setup all notification widgets
splash = new SplashScreenHelper(SplashScreen.getSplashScreen());
BaseNoGui.notifier = new GUIUserNotifier(this);

// Setup the theme coloring fun
Theme.init();
System.setProperty("swing.aatext", PreferencesData.get("editor.antialias", "true"));

// Set the look and feel before opening the window
try {
BaseNoGui.getPlatform().setLookAndFeel();
} catch (Exception e) {
// ignore
}

// Use native popups so they don't look so crappy on osx
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
} else {
splash = new SplashScreenHelper(null);
}

splash.splashText(tr("Loading configuration..."));

BaseNoGui.initVersion();

// Don't put anything above this line that might make GUI,
// because the platform has to be inited properly first.

// Create a location for untitled sketches
untitledFolder = FileUtils.createTempFolder("untitled" + new Random().nextInt(Integer.MAX_VALUE), ".tmp");
DeleteFilesOnShutdown.add(untitledFolder);

BaseNoGui.checkInstallationFolder();

Expand All @@ -246,11 +245,15 @@ public Base(String[] args) throws Exception {
}
}

splashScreenHelper.splashText(tr("Initializing packages..."));
splash.splashText(tr("Initializing packages..."));
BaseNoGui.initPackages();
splashScreenHelper.splashText(tr("Preparing boards..."));
rebuildBoardsMenu();
rebuildProgrammerMenu();

splash.splashText(tr("Preparing boards..."));

if (!isCommandLine()) {
rebuildBoardsMenu();
rebuildProgrammerMenu();
}

// Setup board-dependent variables.
onBoardOrPortChange();
Expand All @@ -263,35 +266,6 @@ public Base(String[] args) throws Exception {

parser.parseArgumentsPhase2();

for (String path : parser.getFilenames()) {
// 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 (OSUtils.isWindows()) {
try {
file = file.getCanonicalFile();
} catch (IOException e) {
e.printStackTrace();
}
}

boolean showEditor = parser.isGuiMode();
if (!parser.isForceSavePrefs())
PreferencesData.setDoSave(showEditor);
if (handleOpen(file, retrieveSketchLocation(".default"), showEditor, false) == null) {
String mess = I18n.format(tr("Failed to open sketch: \"{0}\""), path);
// Open failure is fatal in upload/verify mode
if (parser.isVerifyOrUploadMode())
showError(null, mess, 2);
else
showWarning(null, mess, null);
}
}

// Save the preferences. For GUI mode, this happens in the quit
// handler, but for other modes we should also make sure to save
// them.
Expand Down Expand Up @@ -377,35 +351,90 @@ public Base(String[] args) throws Exception {
System.exit(0);

} else if (parser.isVerifyOrUploadMode()) {
splashScreenHelper.close();
// Set verbosity for command line build
PreferencesData.set("build.verbose", "" + parser.isDoVerboseBuild());
PreferencesData.set("upload.verbose", "" + parser.isDoVerboseUpload());
PreferencesData.set("runtime.preserve.temp.files", Boolean.toString(parser.isPreserveTempFiles()));
PreferencesData.setBoolean("build.verbose", parser.isDoVerboseBuild());
PreferencesData.setBoolean("upload.verbose", parser.isDoVerboseUpload());

// Make sure these verbosity preferences are only for the
// current session
// Set preserve-temp flag
PreferencesData.setBoolean("runtime.preserve.temp.files", parser.isPreserveTempFiles());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps changing set to setBoolean should end up in a separate commit?


// Make sure these verbosity preferences are only for the current session
PreferencesData.setDoSave(false);

Editor editor = editors.get(0);
Sketch sketch = null;
String outputFile = null;

if (parser.isUploadMode()) {
splashScreenHelper.splashText(tr("Verifying and uploading..."));
editor.exportHandler.run();
} else {
splashScreenHelper.splashText(tr("Verifying..."));
editor.runHandler.run();
}
try {
// Build
splash.splashText(tr("Verifying..."));

File sketchFile = new File(parser.getFilenames().get(0));
sketch = new Sketch(sketchFile);

// Error during build or upload
if (editor.status.isErr()) {
outputFile = new Compiler(sketch).build(progress -> {}, false);
} catch (Exception e) {
// Error during build
System.exit(1);
}

if (parser.isUploadMode()) {
// Upload
splash.splashText(tr("Uploading..."));

try {
List<String> warnings = new ArrayList<>();
UploaderUtils uploader = new UploaderUtils();
boolean res = uploader.upload(sketch, null, outputFile,
parser.isDoUseProgrammer(),
parser.isNoUploadPort(), warnings);
for (String warning : warnings) {
System.out.println(tr("Warning") + ": " + warning);
}
if (!res) {
throw new Exception();
}
} catch (Exception e) {
// Error during upload
System.out.flush();
System.err.flush();
System.err
.println(tr("An error occurred while uploading the sketch"));
System.exit(1);
}
}

// No errors exit gracefully
System.exit(0);
} else if (parser.isGuiMode()) {
splashScreenHelper.splashText(tr("Starting..."));
splash.splashText(tr("Starting..."));

for (String path : parser.getFilenames()) {
// 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 (OSUtils.isWindows()) {
try {
file = file.getCanonicalFile();
} catch (IOException e) {
e.printStackTrace();
}
}

if (!parser.isForceSavePrefs())
PreferencesData.setDoSave(true);
if (handleOpen(file, retrieveSketchLocation(".default"), false) == null) {
String mess = I18n.format(tr("Failed to open sketch: \"{0}\""), path);
// Open failure is fatal in upload/verify mode
if (parser.isVerifyOrUploadMode())
showError(null, mess, 2);
else
showWarning(null, mess, null);
}
}

installKeyboardInputMap();

Expand Down Expand Up @@ -472,7 +501,7 @@ protected boolean restoreSketches() throws Exception {
}
int[] location = retrieveSketchLocation("" + i);
// If file did not exist, null will be returned for the Editor
if (handleOpen(new File(path), location, nextEditorLocation(), true, false, false) != null) {
if (handleOpen(new File(path), location, nextEditorLocation(), false, false) != null) {
opened++;
}
}
Expand Down Expand Up @@ -764,14 +793,14 @@ public Editor handleOpen(File file) throws Exception {
}

public Editor handleOpen(File file, boolean untitled) throws Exception {
return handleOpen(file, nextEditorLocation(), true, untitled);
return handleOpen(file, nextEditorLocation(), untitled);
}

protected Editor handleOpen(File file, int[] location, boolean showEditor, boolean untitled) throws Exception {
return handleOpen(file, location, location, showEditor, true, untitled);
protected Editor handleOpen(File file, int[] location, boolean untitled) throws Exception {
return handleOpen(file, location, location, true, untitled);
}

protected Editor handleOpen(File file, int[] storedLocation, int[] defaultLocation, boolean showEditor, boolean storeOpenedSketches, boolean untitled) throws Exception {
protected Editor handleOpen(File file, int[] storedLocation, int[] defaultLocation, boolean storeOpenedSketches, boolean untitled) throws Exception {
if (!file.exists()) return null;

// Cycle through open windows to make sure that it's not already open.
Expand Down Expand Up @@ -804,9 +833,7 @@ protected Editor handleOpen(File file, int[] storedLocation, int[] defaultLocati

// now that we're ready, show the window
// (don't do earlier, cuz we might move it based on a window being closed)
if (showEditor) {
SwingUtilities.invokeLater(() -> editor.setVisible(true));
}
SwingUtilities.invokeLater(() -> editor.setVisible(true));

return editor;
}
Expand Down Expand Up @@ -1810,10 +1837,9 @@ public List<JMenu> getBoardsCustomMenus() {
}

public File getDefaultSketchbookFolderOrPromptForIt() {

File sketchbookFolder = BaseNoGui.getDefaultSketchbookFolder();

if (sketchbookFolder == null) {
if (sketchbookFolder == null && !isCommandLine()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this not break below, when sketchbookFolder is null and sketchbookFolder.exists() is called? This seems to be a bit of a corner case, since it only occurs when the default sketchbook path (as returned by Platform.getDefaultSketchbookFolder()) is null. I'm not exactly sure how if this should not normally happen, or if this will happen if the default path does not exist (but judging from the mkdirs() a bit further down, it's probably the former).

Looking through the code to see how this works, it seems that the responsibility for resolving the sketchbook path might be too much spread out right now, so perhaps some additional refactoring should be done after this PR in this area.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you noticed the folders handling code is spread around the IDE, and it needs a bit of love :-) Actually, I tried to factor all the folder handling code in a single class while doing this PR, but at some point I've just dropped this task to reduce the possibility of regressions.

The rationale behind this change is:

  • if my calculations are correct BaseNoGui.getDefaultSketchbookFolder() will never return null
  • this means that the promptSketchbookLocation() will never be called (and could be probably removed altogether)

but since I decided to not touch the folder handling functions in this PR, I opted to just leave it as it is and just add the "guard" to not invoke the file selector in cmd-line mode and let the IDE crash with a NPE (if that code path is ever taken in some obscure ways).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds reasonable.

sketchbookFolder = promptSketchbookLocation();
}

Expand Down