Skip to content

Commit c3269fb

Browse files
author
jantje
committed
#1388 during testing experienced #1394
1 parent 878cfe2 commit c3269fb

File tree

4 files changed

+280
-114
lines changed

4 files changed

+280
-114
lines changed

io.sloeber.core/src/cc/arduino/packages/ssh/SSH.java

+128-76
Original file line numberDiff line numberDiff line change
@@ -29,93 +29,145 @@
2929

3030
package cc.arduino.packages.ssh;
3131

32+
import java.io.BufferedReader;
3233
import java.io.IOException;
3334
import java.io.InputStream;
35+
import java.io.InputStreamReader;
3436

37+
import org.eclipse.core.runtime.IStatus;
38+
import org.eclipse.core.runtime.Status;
3539
import org.eclipse.ui.console.MessageConsoleStream;
3640

3741
import com.jcraft.jsch.Channel;
3842
import com.jcraft.jsch.ChannelExec;
3943
import com.jcraft.jsch.JSchException;
4044
import com.jcraft.jsch.Session;
4145

42-
@SuppressWarnings({ "nls","unused" })
46+
import io.sloeber.core.Messages;
47+
import io.sloeber.core.common.Common;
48+
import io.sloeber.core.common.Const;
49+
50+
@SuppressWarnings({ "nls", "unused" })
4351
public class SSH {
4452

45-
final Session session;
46-
47-
public SSH(Session session) {
48-
this.session = session;
49-
}
50-
51-
public boolean execSyncCommand(String command) throws JSchException, IOException {
52-
return execSyncCommand(command, null, null);
53-
}
54-
55-
@SuppressWarnings("resource")
56-
public boolean execSyncCommand(String command, MessageConsoleStream stdoutConsumer,
57-
MessageConsoleStream stderrConsumer) throws JSchException, IOException {
58-
InputStream stdout = null;
59-
InputStream stderr = null;
60-
Channel channel = null;
61-
try {
62-
channel = session.openChannel("exec");
63-
((ChannelExec) channel).setCommand(command);
64-
65-
channel.setInputStream(null);
66-
67-
stdout = channel.getInputStream();
68-
stderr = ((ChannelExec) channel).getErrStream();
69-
70-
channel.connect();
71-
72-
int exitCode = consumeOutputSyncAndReturnExitCode(channel);
73-
74-
return exitCode == 0;
75-
76-
} finally {
77-
try {
78-
if (stdout != null) {
79-
stdout.close();
80-
}
81-
if (stderr != null) {
82-
stderr.close();
83-
}
84-
} catch (IOException e) {
85-
e.printStackTrace();
86-
}
87-
if (channel != null) {
88-
channel.disconnect();
89-
}
90-
}
91-
}
92-
93-
private static int consumeOutputSyncAndReturnExitCode(Channel channel) {
94-
while (true) {
95-
96-
if (channel.isClosed()) {
97-
return channel.getExitStatus();
98-
}
99-
try {
100-
Thread.sleep(100);
101-
} catch (Exception ee) {
102-
// noop
103-
}
104-
}
105-
}
106-
107-
// @SuppressWarnings("static-method")
108-
// private void consumeStream(byte[] buffer, InputStream in, PrintStream
109-
// out) throws IOException {
110-
// while (in.available() > 0) {
111-
// int length = in.read(buffer, 0, buffer.length);
112-
// if (length < 0) {
113-
// break;
114-
// }
115-
// if (out != null) {
116-
// out.print(new String(buffer, 0, length));
117-
// }
118-
// }
119-
// }
53+
final Session session;
54+
55+
public SSH(Session session) {
56+
this.session = session;
57+
}
58+
59+
public boolean execSyncCommand(String command) throws JSchException, IOException {
60+
return execSyncCommand(command, null, null);
61+
}
62+
63+
public boolean execSyncCommand(String command, MessageConsoleStream stdoutStream,
64+
MessageConsoleStream stderrConsumer) throws JSchException, IOException {
65+
ChannelExec channel = (ChannelExec) session.openChannel("exec");
66+
67+
try (InputStream stdout = channel.getInputStream(); InputStream stderr = channel.getErrStream();) {
68+
69+
channel.setCommand(command);
70+
71+
channel.setInputStream(null);
72+
73+
// for one reason or another I need to swap error and output stream here
74+
Thread stdoutRunner = new Thread(new LogStreamRunner(stderr, stdoutStream));
75+
Thread stderrRunner = new Thread(new LogStreamRunner(stdout, stderrConsumer));
76+
stdoutRunner.start();
77+
stderrRunner.start();
78+
79+
channel.connect();
80+
81+
int exitCode = consumeOutputSyncAndReturnExitCode(channel);
82+
83+
return exitCode == 0;
84+
85+
} finally {
86+
if (channel != null) {
87+
channel.disconnect();
88+
}
89+
}
90+
}
91+
92+
private static int consumeOutputSyncAndReturnExitCode(Channel channel) {
93+
while (true) {
94+
95+
if (channel.isClosed()) {
96+
return channel.getExitStatus();
97+
}
98+
try {
99+
Thread.sleep(100);
100+
} catch (Exception ee) {
101+
// noop
102+
}
103+
}
104+
}
105+
106+
/**
107+
* A runnable class that will read a Stream until EOF, storing each line in a
108+
* List and also calling a listener for each line.
109+
*/
110+
private class LogStreamRunner implements Runnable {
111+
112+
private final BufferedReader fReader;
113+
private MessageConsoleStream fConsoleOutput = null;
114+
115+
/**
116+
* Construct a Streamrunner that will read the given InputStream and log all
117+
* lines in the given List.
118+
* <p>
119+
* If a valid <code>OutputStream</code> is set, everything read by this
120+
* <code>LogStreamRunner</code> is also written to it.
121+
*
122+
* @param instream
123+
* <code>InputStream</code> to read
124+
* @param log
125+
* <code>List&lt;String&gt;</code> where all lines of the instream
126+
* are stored
127+
* @param consolestream
128+
* <code>OutputStream</code> for secondary console output, or
129+
* <code>null</code> for no console output.
130+
*/
131+
public LogStreamRunner(InputStream instream, MessageConsoleStream consolestream) {
132+
this.fReader = new BufferedReader(new InputStreamReader(instream));
133+
this.fConsoleOutput = consolestream;
134+
}
135+
136+
/*
137+
* (non-Javadoc)
138+
*
139+
* @see java.lang.Runnable#run()
140+
*/
141+
@Override
142+
public void run() {
143+
try {
144+
for (;;) {
145+
// Processes a new process output line.
146+
// If a Listener has been registered, call it
147+
int read = this.fReader.read();
148+
if (read != -1) {
149+
String readChar = new String() + (char) read;
150+
151+
// And print to the console (if active)
152+
if (this.fConsoleOutput != null) {
153+
this.fConsoleOutput.print(readChar);
154+
}
155+
} else {
156+
break;
157+
}
158+
}
159+
} catch (IOException e) {
160+
// This is unlikely to happen, but log it nevertheless
161+
IStatus status = new Status(IStatus.ERROR, Const.CORE_PLUGIN_ID, Messages.command_io, e);
162+
Common.log(status);
163+
} finally {
164+
try {
165+
this.fReader.close();
166+
} catch (IOException e) {
167+
// can't do anything
168+
}
169+
}
170+
}
171+
}
120172

121173
}

io.sloeber.core/src/io/sloeber/core/api/BoardDescription.java

+15-20
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ public class BoardDescription {
7474
private String myBoardID = EMPTY;
7575
private Map<String, String> myOptions = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
7676

77-
7877
/*
7978
* Stuff to make things work
8079
*/
@@ -94,7 +93,6 @@ public class BoardDescription {
9493
private final String KEY_SLOEBER_UPLOAD_PORT = "UPLOAD.PORT"; //$NON-NLS-1$
9594
private final String KEY_SLOEBER_MENU_SELECTION = "BOARD.MENU"; //$NON-NLS-1$
9695

97-
9896
@Override
9997
public String toString() {
10098
return getReferencingBoardsFile() + " \"" + getBoardName() + "\" " + getUploadPort(); //$NON-NLS-1$//$NON-NLS-2$
@@ -357,8 +355,6 @@ public BoardDescription(BoardDescription srcObject) {
357355
myOptions = new TreeMap<>(srcObject.myOptions);
358356
}
359357

360-
361-
362358
public String getuploadTool() {
363359
return this.myUploadTool;
364360
}
@@ -398,7 +394,6 @@ public void saveUserSelection() {
398394
myStorageNode.put(KEY_LAST_USED_BOARD_MENU_OPTIONS, KeyValue.makeString(this.myOptions));
399395
}
400396

401-
402397
public String getArchitecture() {
403398
return this.myBoardTxtFile.getArchitecture();
404399
}
@@ -526,7 +521,6 @@ public String[] getMenuItemNamesFromMenuID(String menuID) {
526521
return this.myBoardTxtFile.getMenuItemNamesFromMenuID(menuID, this.myBoardID);
527522
}
528523

529-
530524
public TreeMap<String, IPath> getAllExamples() {
531525
updateWhenDirty();
532526
return LibraryManager.getAllExamples(this);
@@ -661,7 +655,6 @@ public String getUploadPatternKey() {
661655
return TOOLS + DOT + upLoadTool + DOT + UPLOAD + DOT + networkPrefix + PATTERN;
662656
}
663657

664-
665658
public IPath getreferencedHardwarePath() {
666659
updateWhenDirty();
667660
IPath platformPath = getReferencedCorePlatformPath();
@@ -701,7 +694,6 @@ public boolean isNetworkUpload() {
701694
return getHost() != null;
702695
}
703696

704-
705697
protected BoardDescription(File txtFile, String boardID) {
706698
this.myBoardID = boardID;
707699
this.myreferencingBoardsFile = txtFile;
@@ -730,7 +722,6 @@ protected BoardDescription(File txtFile, String boardID) {
730722
}
731723
}
732724

733-
734725
private Map<String, String> onlyKeepValidOptions(Map<String, String> options) {
735726
Map<String, String> ret = new HashMap<>();
736727

@@ -824,7 +815,6 @@ public Map<String, String> getEnvVars() {
824815
allVars.put(ENV_KEY_HARDWARE_PATH, getreferencedHardwarePath().toOSString());
825816
allVars.put(ENV_KEY_PLATFORM_PATH, getreferencingPlatformPath().toOSString());
826817

827-
828818
allVars.put(ENV_KEY_SERIAL_PORT, getActualUploadPort());
829819
allVars.put(ENV_KEY_SERIAL_DOT_PORT, getActualUploadPort());
830820

@@ -846,7 +836,6 @@ public Map<String, String> getEnvVars() {
846836
allVars.put(ENV_KEY_REFERENCED_VARIANT_PLATFORM_PATH, getReferencedVariantPlatformPath().toOSString());
847837
allVars.put(ENV_KEY_REFERENCED_UPLOAD_PLATFORM_PATH, getReferencedUploadPlatformPath().toOSString());
848838

849-
850839
PlatformTxtFile referencedPlatfromFile = getreferencedPlatformFile();
851840
// process the platform file referenced by the boards.txt
852841
if (referencedPlatfromFile != null) {
@@ -861,12 +850,10 @@ public Map<String, String> getEnvVars() {
861850
// put in the installed tools info
862851
allVars.putAll(getEnVarPlatformInfo());
863852

864-
865-
866853
Programmers localProgrammers[] = Programmers.fromBoards(this);
867854
String programmer = getProgrammer();
868855
for (Programmers curProgrammer : localProgrammers) {
869-
// allVars.putAll(curProgrammer.getAllEnvironVars());
856+
// allVars.putAll(curProgrammer.getAllEnvironVars());
870857
String programmerID = curProgrammer.getIDFromNiceName(programmer);
871858
if (programmerID != null) {
872859
allVars.putAll(curProgrammer.getAllEnvironVars(programmerID));
@@ -1069,18 +1056,18 @@ public static BoardDescription getFromCDT(ICConfigurationDescription confDesc) {
10691056
ret.myBoardID = getOldWayEnvVar(confDesc, "JANTJE.board_ID");
10701057
String optinconcat = getOldWayEnvVar(confDesc, "JANTJE.menu");
10711058
ret.myOptions = KeyValue.makeMap(optinconcat);
1072-
1059+
10731060
String referencingBoardsFile = getOldWayEnvVar(confDesc, "JANTJE.boards_file");
1074-
int packagesIndex=referencingBoardsFile.indexOf( "\\arduinoPlugin\\packages\\");
1075-
if(packagesIndex==-1) {
1076-
packagesIndex=referencingBoardsFile.indexOf( "/arduinoPlugin/packages/");
1061+
int packagesIndex = referencingBoardsFile.indexOf("\\arduinoPlugin\\packages\\");
1062+
if (packagesIndex == -1) {
1063+
packagesIndex = referencingBoardsFile.indexOf("/arduinoPlugin/packages/");
10771064
}
1078-
if(packagesIndex!=-1) {
1065+
if (packagesIndex != -1) {
10791066
referencingBoardsFile = sloeberHomePath.append(referencingBoardsFile.substring(packagesIndex)).toString();
10801067
}
10811068
ret.myreferencingBoardsFile = resolvePathEnvironmentString(new File(referencingBoardsFile));
10821069
ret.myBoardTxtFile = new BoardTxtFile(ret.myreferencingBoardsFile);
1083-
1070+
10841071
return ret;
10851072
}
10861073

@@ -1100,4 +1087,12 @@ public Map<String, String> getAllMenus() {
11001087
return myBoardTxtFile.getMenus();
11011088
}
11021089

1090+
public boolean isSSHUpload() {
1091+
if (!isNetworkUpload()) {
1092+
return false;
1093+
}
1094+
// This is a hardcoded fix. Not sure how to do better
1095+
return myBoardID.equals("yun"); //$NON-NLS-1$
1096+
}
1097+
11031098
}

io.sloeber.core/src/io/sloeber/core/api/SloeberProject.java

+11
Original file line numberDiff line numberDiff line change
@@ -1140,4 +1140,15 @@ public IStatus upload() {
11401140
}
11411141
}
11421142

1143+
public IFile getTargetFile() {
1144+
// I assume the extension is .hex as the Arduino Framework does not provide the
1145+
// extension nor a key for the uploadable sketch (=build target)
1146+
// as currently this method is only used for network upload via yun this is ok
1147+
// nor now
1148+
CCorePlugin cCorePlugin = CCorePlugin.getDefault();
1149+
ICProjectDescription prjCDesc = cCorePlugin.getProjectDescription(myProject);
1150+
String activeConfig = prjCDesc.getActiveConfiguration().getName();
1151+
return myProject.getFolder(activeConfig).getFile(myProject.getName() + ".hex");
1152+
}
1153+
11431154
}

0 commit comments

Comments
 (0)