Commit | Line | Data |
---|---|---|
d132bcc7 | 1 | /********************************************************************** |
ed902a2b | 2 | * Copyright (c) 2012, 2015 Ericsson |
cfdb727a | 3 | * |
d132bcc7 BH |
4 | * All rights reserved. This program and the accompanying materials are |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
cfdb727a AM |
8 | * |
9 | * Contributors: | |
d132bcc7 | 10 | * Bernd Hufmann - Initial API and implementation |
b732adaa | 11 | * Markus Schorn - Bug 448058: Use org.eclipse.remote in favor of RSE |
d132bcc7 | 12 | **********************************************************************/ |
9bc60be7 | 13 | package org.eclipse.tracecompass.internal.lttng2.control.stubs.shells; |
d132bcc7 | 14 | |
13729cbc BH |
15 | import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
16 | ||
d132bcc7 BH |
17 | import java.io.BufferedReader; |
18 | import java.io.DataInputStream; | |
3d09f0a5 | 19 | import java.io.File; |
d132bcc7 | 20 | import java.io.FileInputStream; |
13729cbc | 21 | import java.io.IOException; |
d132bcc7 | 22 | import java.io.InputStreamReader; |
3d09f0a5 | 23 | import java.io.PrintWriter; |
d132bcc7 BH |
24 | import java.util.ArrayList; |
25 | import java.util.Collection; | |
26 | import java.util.HashMap; | |
27 | import java.util.Iterator; | |
28 | import java.util.List; | |
29 | import java.util.Map; | |
30 | import java.util.regex.Matcher; | |
31 | import java.util.regex.Pattern; | |
32 | ||
33 | import org.eclipse.core.commands.ExecutionException; | |
325d8cac BH |
34 | import org.eclipse.core.resources.IWorkspace; |
35 | import org.eclipse.core.resources.ResourcesPlugin; | |
d132bcc7 | 36 | import org.eclipse.core.runtime.IProgressMonitor; |
aa353506 | 37 | import org.eclipse.jdt.annotation.NonNull; |
1d6a2139 | 38 | import org.eclipse.tracecompass.internal.tmf.remote.core.stubs.shells.TestCommandShell; |
364dcfaf | 39 | import org.eclipse.tracecompass.tmf.remote.core.shell.ICommandInput; |
90700072 | 40 | import org.eclipse.tracecompass.tmf.remote.core.shell.ICommandOutputListener; |
ec619615 | 41 | import org.eclipse.tracecompass.tmf.remote.core.shell.ICommandResult; |
d132bcc7 | 42 | |
cfdb727a | 43 | @SuppressWarnings("javadoc") |
d132bcc7 BH |
44 | public class LTTngToolsFileShell extends TestCommandShell { |
45 | ||
46 | // ------------------------------------------------------------------------ | |
47 | // CONSTANTS | |
48 | // ------------------------------------------------------------------------ | |
4e0b52e0 AM |
49 | private final static String SCENARIO_KEY = "<SCENARIO>"; |
50 | private final static String SCENARIO_END_KEY = "</SCENARIO>"; | |
51 | private final static String INPUT_KEY = "<COMMAND_INPUT>"; | |
52 | private final static String INPUT_END_KEY = "</COMMAND_INPUT>"; | |
53 | private final static String RESULT_KEY = "<COMMAND_RESULT>"; | |
4e0b52e0 AM |
54 | private final static String OUTPUT_KEY = "<COMMAND_OUTPUT>"; |
55 | private final static String OUTPUT_END_KEY = "</COMMAND_OUTPUT>"; | |
6418ef54 JRJ |
56 | private final static String ERROR_OUTPUT_KEY = "<COMMAND_ERROR_OUTPUT>"; |
57 | private final static String ERROR_OUTPUT_END_KEY = "</COMMAND_ERROR_OUTPUT>"; | |
4e0b52e0 | 58 | private final static String COMMENT_KEY = "#.*"; |
cfdb727a | 59 | |
774a7993 | 60 | private final static Pattern LTTNG_LIST_SESSION_PATTERN = Pattern.compile("lttng\\s+list\\s+(.+)"); |
4e0b52e0 | 61 | private final static String LTTNG_LIST_PROVIDER_PATTERN = "lttng\\s+list\\s+(-u|-k)"; |
d132bcc7 | 62 | |
2e65d221 BH |
63 | private final static Pattern LTTNG_LIST_SESSION_MI_PATTERN = Pattern.compile("lttng\\s+--mi xml\\s+list\\s+(.+)"); |
64 | private final static String LTTNG_LIST_PROVIDER_MI_PATTERN = "lttng\\s+--mi xml\\s+list\\s+(-u|-k)"; | |
65 | ||
3d09f0a5 | 66 | private final static String LTTNG_USER_HOME_PATTERN = "\\$\\{userhome\\}"; |
325d8cac | 67 | private final static String LTTNG_WORKSPACE_PATTERN = "\\$\\{workspace\\}"; |
921151cf BH |
68 | private final static String SESSION_NAME_PATTERN = "\\$\\{sessionname\\}"; |
69 | ||
3d09f0a5 | 70 | private final static String USER_HOME = System.getProperty("user.home"); |
325d8cac | 71 | private final static String WORKSPACE_HOME; |
3d09f0a5 BH |
72 | |
73 | private final static Pattern LTTNG_SAVE_MI_PATTERN = Pattern.compile("lttng\\s+--mi xml\\s+save\\s+-f"); | |
74 | ||
75 | private final static String PROFILE_PATH_STRING = USER_HOME + '/' + ".lttng" + '/' + "sessions"; | |
76 | ||
325d8cac BH |
77 | static { |
78 | IWorkspace workspace = ResourcesPlugin.getWorkspace(); | |
79 | //get location of workspace (java.io.File) | |
80 | File workspaceDirectory = workspace.getRoot().getLocation().toFile(); | |
81 | WORKSPACE_HOME = workspaceDirectory.toString(); | |
82 | } | |
83 | ||
d132bcc7 BH |
84 | // ------------------------------------------------------------------------ |
85 | // Attributes | |
86 | // ------------------------------------------------------------------------ | |
87 | private String fScenariofile; | |
88 | private String fScenario; | |
3d09f0a5 BH |
89 | private String fProfileName = null; |
90 | private File fProfileFile = null; | |
921151cf | 91 | private String fSessionName = null; |
d132bcc7 | 92 | |
e0838ca1 AM |
93 | private final Map<String, Map<String, ICommandResult>> fScenarioMap = new HashMap<>(); |
94 | private final Map<String, Integer> fSessionNameMap = new HashMap<>(); | |
d132bcc7 BH |
95 | |
96 | /** | |
97 | * Parse a scenario file with the format: | |
774a7993 | 98 | * |
6418ef54 JRJ |
99 | * <pre> |
100 | * <SCENARIO> | |
d132bcc7 | 101 | * ScenarioName |
cfdb727a | 102 | * |
6418ef54 | 103 | * <COMMAND_INPUT> |
d132bcc7 | 104 | * Command |
4888aef9 | 105 | * </COMMAND_INPUT> |
cfdb727a | 106 | * |
6418ef54 | 107 | * <COMMAND_RESULT> |
d132bcc7 | 108 | * CommandResult |
6418ef54 | 109 | * </COMMAND_RESULT> |
cfdb727a | 110 | * |
6418ef54 | 111 | * <COMMAND_OUTPUT> |
d132bcc7 | 112 | * CommandOutput |
6418ef54 JRJ |
113 | * <COMMAND_ERROR_OUTPUT> |
114 | * CommandErrorOutput | |
115 | * </COMMAND_ERROR_OUTPUT> | |
116 | * </COMMAND_OUTPUT> | |
cfdb727a | 117 | * |
6418ef54 | 118 | * </SCENARIO> |
cfdb727a | 119 | * |
d132bcc7 BH |
120 | * Where: ScenarioName - is the scenario name |
121 | * Command - the command line string | |
122 | * CommandResult - the result integer of the command (0 for success, 1 for failure) | |
4888aef9 MAL |
123 | * CommandOutput - the command output string (multi-line possible) |
124 | * CommandErrorOutput - the command error output string (multi-line possible) | |
cfdb727a | 125 | * |
d132bcc7 BH |
126 | * Note: 1) There can be many scenarios per file |
127 | * 2) There can be many (Command-CommandResult-CommandOutput) triples per scenario | |
774a7993 BH |
128 | * 3) Lines starting with # will be ignored (comments) |
129 | * | |
6418ef54 | 130 | * <pre> |
d132bcc7 | 131 | * @param scenariofile - path to scenario file |
d132bcc7 | 132 | */ |
13729cbc | 133 | public synchronized void loadScenarioFile(String scenariofile) { |
d132bcc7 | 134 | fScenariofile = scenariofile; |
cfdb727a | 135 | |
d132bcc7 BH |
136 | // clean up map |
137 | Collection<Map<String, ICommandResult>> values = fScenarioMap.values(); | |
138 | for (Iterator<Map<String, ICommandResult>> iterator = values.iterator(); iterator.hasNext();) { | |
cfdb727a | 139 | Map<String, ICommandResult> map = iterator.next(); |
d132bcc7 BH |
140 | map.clear(); |
141 | } | |
142 | fScenarioMap.clear(); | |
cfdb727a | 143 | |
d132bcc7 | 144 | // load from file |
cfdb727a | 145 | |
d132bcc7 | 146 | // Open the file |
e0838ca1 AM |
147 | try (FileInputStream fstream = new FileInputStream(fScenariofile); |
148 | DataInputStream in = new DataInputStream(fstream); | |
149 | BufferedReader br = new BufferedReader(new InputStreamReader(in));) { | |
150 | String strLine; | |
cfdb727a | 151 | |
e0838ca1 | 152 | // Read File Line by Line |
cfdb727a | 153 | |
e0838ca1 AM |
154 | // Temporary map for generating instance numbers for lttng list |
155 | // <session> commands. | |
156 | // The numbers are per scenario. | |
157 | Map<String, Integer> tmpSessionNameMap = new HashMap<>(); | |
158 | while ((strLine = br.readLine()) != null) { | |
d132bcc7 BH |
159 | |
160 | // Ignore comments | |
e0838ca1 AM |
161 | if (isComment(strLine)) { |
162 | continue; | |
d132bcc7 BH |
163 | } |
164 | ||
e0838ca1 AM |
165 | if (SCENARIO_KEY.equals(strLine)) { |
166 | // scenario start | |
167 | ||
cfdb727a | 168 | // Ignore comments |
e0838ca1 AM |
169 | strLine = br.readLine(); |
170 | while (isComment(strLine)) { | |
171 | strLine = br.readLine(); | |
d132bcc7 BH |
172 | } |
173 | ||
e0838ca1 AM |
174 | String scenario = strLine; |
175 | Map<String, ICommandResult> commandMap = new HashMap<>(); | |
176 | fScenarioMap.put(scenario, commandMap); | |
177 | List<String> output = null; | |
6418ef54 | 178 | List<String> errorOutput = null; |
e0838ca1 AM |
179 | String input = null; |
180 | boolean inOutput = false; | |
6418ef54 | 181 | boolean inErrorOutput = false; |
e0838ca1 AM |
182 | int result = 0; |
183 | tmpSessionNameMap.clear(); | |
184 | while ((strLine = br.readLine()) != null) { | |
d132bcc7 | 185 | // Ignore comments |
e0838ca1 AM |
186 | if (isComment(strLine)) { |
187 | continue; | |
d132bcc7 | 188 | } |
e0838ca1 AM |
189 | |
190 | if (SCENARIO_END_KEY.equals(strLine)) { | |
191 | // Scenario is finished | |
192 | break; | |
d132bcc7 | 193 | } |
e0838ca1 | 194 | if (INPUT_KEY.equals(strLine)) { |
d132bcc7 | 195 | strLine = br.readLine(); |
e0838ca1 AM |
196 | // Ignore comments |
197 | while (isComment(strLine)) { | |
198 | strLine = br.readLine(); | |
199 | } | |
200 | // Read command | |
201 | input = strLine; | |
202 | ||
325d8cac | 203 | // Update userhome |
3d09f0a5 BH |
204 | input = input.replaceAll(LTTNG_USER_HOME_PATTERN, USER_HOME); |
205 | ||
325d8cac BH |
206 | // Update workspace |
207 | input = input.replaceAll(LTTNG_WORKSPACE_PATTERN, WORKSPACE_HOME); | |
208 | ||
921151cf BH |
209 | // Update session variable |
210 | if (fSessionName != null) { | |
211 | input = input.replaceAll(SESSION_NAME_PATTERN, fSessionName); | |
212 | } | |
213 | ||
e0838ca1 | 214 | // Handle instances of 'lttng list |
4888aef9 | 215 | // <session"-command |
e0838ca1 | 216 | Matcher matcher = LTTNG_LIST_SESSION_PATTERN.matcher(strLine); |
2e65d221 | 217 | Matcher miMatcher = LTTNG_LIST_SESSION_MI_PATTERN.matcher(strLine); |
3d09f0a5 | 218 | |
e0838ca1 AM |
219 | if (matcher.matches() && !input.matches(LTTNG_LIST_PROVIDER_PATTERN)) { |
220 | String sessionName = matcher.group(1).trim(); | |
2e65d221 BH |
221 | input += updateSessionMap(tmpSessionNameMap, input, sessionName); |
222 | } else if (miMatcher.matches() && !input.matches(LTTNG_LIST_PROVIDER_MI_PATTERN)) { | |
223 | String sessionName = miMatcher.group(1).trim(); | |
224 | input += updateSessionMap(tmpSessionNameMap, input, sessionName); | |
e0838ca1 AM |
225 | } |
226 | } else if (INPUT_END_KEY.equals(strLine)) { | |
227 | // Initialize output array | |
228 | output = new ArrayList<>(); | |
6418ef54 | 229 | errorOutput = new ArrayList<>(); |
e0838ca1 | 230 | } else if (RESULT_KEY.equals(strLine)) { |
d132bcc7 | 231 | strLine = br.readLine(); |
e0838ca1 AM |
232 | // Ignore comments |
233 | while (isComment(strLine)) { | |
234 | strLine = br.readLine(); | |
235 | } | |
236 | // Save result value | |
237 | result = Integer.parseInt(strLine); | |
238 | } else if (OUTPUT_END_KEY.equals(strLine)) { | |
239 | // Save output/result in command map | |
6418ef54 | 240 | if (output != null && errorOutput != null) { |
1d6a2139 | 241 | commandMap.put(input, createCommandResult(result, |
0e4f957e AM |
242 | output.toArray(new @NonNull String[output.size()]), |
243 | errorOutput.toArray(new @NonNull String[errorOutput.size()]))); | |
e0838ca1 AM |
244 | } |
245 | inOutput = false; | |
246 | } else if (OUTPUT_KEY.equals(strLine)) { | |
247 | // first line of output | |
248 | inOutput = true; | |
6418ef54 JRJ |
249 | } else if (ERROR_OUTPUT_KEY.equals(strLine)) { |
250 | // first line of output | |
251 | inErrorOutput = true; | |
252 | } else if (ERROR_OUTPUT_END_KEY.equals(strLine)) { | |
253 | inErrorOutput = false; | |
254 | } else if (inOutput) { | |
e0838ca1 AM |
255 | while (isComment(strLine)) { |
256 | strLine = br.readLine(); | |
257 | } | |
921151cf | 258 | |
325d8cac BH |
259 | // Update userhome |
260 | strLine = strLine.replaceAll(LTTNG_USER_HOME_PATTERN, USER_HOME); | |
261 | ||
262 | // Update workspace | |
263 | strLine = strLine.replaceAll(LTTNG_WORKSPACE_PATTERN, WORKSPACE_HOME); | |
264 | ||
921151cf BH |
265 | // Update session variable |
266 | if (fSessionName != null) { | |
267 | strLine = strLine.replaceAll(SESSION_NAME_PATTERN, fSessionName); | |
268 | } | |
269 | ||
6418ef54 JRJ |
270 | // lines of output/error output |
271 | if (errorOutput != null && inErrorOutput) { | |
272 | errorOutput.add(strLine); | |
273 | } else if (output != null) { | |
e0838ca1 AM |
274 | output.add(strLine); |
275 | } | |
d132bcc7 | 276 | } |
e0838ca1 AM |
277 | // else { |
278 | // if (RESULT_END_KEY.equals(strLine)) { | |
d132bcc7 | 279 | // nothing to do |
e0838ca1 AM |
280 | // } |
281 | } | |
d132bcc7 BH |
282 | } |
283 | } | |
13729cbc BH |
284 | } catch (IOException e) { |
285 | e.printStackTrace(); | |
d132bcc7 | 286 | } |
d132bcc7 BH |
287 | } |
288 | ||
2e65d221 BH |
289 | private static String updateSessionMap(Map<String, Integer> tmpSessionNameMap, String input, String sessionName) { |
290 | Integer i = tmpSessionNameMap.get(sessionName); | |
291 | if (i != null) { | |
292 | i++; | |
293 | } else { | |
294 | i = 0; | |
295 | } | |
296 | tmpSessionNameMap.put(sessionName, i); | |
297 | return String.valueOf(i); | |
298 | } | |
299 | ||
d132bcc7 BH |
300 | // Set the scenario to consider in executeCommand() |
301 | public synchronized void setScenario(String scenario) { | |
302 | fScenario = scenario; | |
303 | fSessionNameMap.clear(); | |
304 | if (!fScenarioMap.containsKey(fScenario)) { | |
305 | throw new IllegalArgumentException(); | |
306 | } | |
307 | } | |
308 | ||
d132bcc7 | 309 | @Override |
364dcfaf | 310 | public synchronized ICommandResult executeCommand(ICommandInput command, IProgressMonitor monitor) throws ExecutionException { |
90700072 BH |
311 | return executeCommand(command, monitor, null); |
312 | } | |
313 | ||
314 | @Override | |
315 | public synchronized ICommandResult executeCommand(ICommandInput command, IProgressMonitor monitor, ICommandOutputListener listener) throws ExecutionException { | |
202956f1 | 316 | Map<String, ICommandResult> commands = checkNotNull(fScenarioMap.get(fScenario)); |
364dcfaf | 317 | String commandLine = command.toString(); |
774a7993 | 318 | String fullCommand = commandLine; |
d132bcc7 | 319 | |
774a7993 | 320 | Matcher matcher = LTTNG_LIST_SESSION_PATTERN.matcher(commandLine); |
2e65d221 | 321 | Matcher miMatcher = LTTNG_LIST_SESSION_MI_PATTERN.matcher(commandLine); |
774a7993 | 322 | if (matcher.matches() && !commandLine.matches(LTTNG_LIST_PROVIDER_PATTERN)) { |
d132bcc7 | 323 | String sessionName = matcher.group(1).trim(); |
2e65d221 BH |
324 | fullCommand += updateSessionMap(fSessionNameMap, fullCommand, sessionName); |
325 | } else if (miMatcher.matches() && !commandLine.matches(LTTNG_LIST_PROVIDER_MI_PATTERN)) { | |
326 | String sessionName = miMatcher.group(1).trim(); | |
327 | fullCommand += updateSessionMap(fSessionNameMap, fullCommand, sessionName); | |
d132bcc7 BH |
328 | } |
329 | ||
41b5c37f | 330 | if (commands.containsKey(fullCommand)) { |
3d09f0a5 BH |
331 | Matcher saveMatcher = LTTNG_SAVE_MI_PATTERN.matcher(fullCommand); |
332 | if (fProfileName != null && saveMatcher.matches()) { | |
333 | try { | |
334 | createProfileFile(); | |
335 | } catch (IOException e) { | |
336 | throw new ExecutionException("Profile file can't be created", e); | |
337 | } | |
338 | } | |
13729cbc | 339 | return checkNotNull(commands.get(fullCommand)); |
cfdb727a | 340 | } |
d132bcc7 | 341 | |
aa353506 | 342 | @NonNull String[] output = new @NonNull String[1]; |
4e0b52e0 | 343 | output[0] = String.valueOf("Command not found"); |
1d6a2139 | 344 | ICommandResult result = createCommandResult(1, output, output); |
4ea599a5 | 345 | return result; |
774a7993 | 346 | } |
cfdb727a | 347 | |
d132bcc7 BH |
348 | // ------------------------------------------------------------------------ |
349 | // Helper methods | |
350 | // ------------------------------------------------------------------------ | |
11252342 | 351 | |
0a78d11a | 352 | private static boolean isComment(String line) { |
1f2f091b | 353 | if (line == null) { |
4e0b52e0 | 354 | throw new RuntimeException("line is null"); |
1f2f091b | 355 | } |
d132bcc7 BH |
356 | return line.matches(COMMENT_KEY); |
357 | } | |
3d09f0a5 BH |
358 | |
359 | private void createProfileFile() throws IOException { | |
360 | if (fProfileName != null) { | |
361 | File path = new File(PROFILE_PATH_STRING); | |
362 | if (!path.exists()) { | |
363 | if (!path.mkdirs()) { | |
364 | throw new RuntimeException(); | |
365 | } | |
366 | } | |
367 | File profileFile = new File(PROFILE_PATH_STRING + '/' + fProfileName + ".lttng"); | |
368 | if (!profileFile.exists()) { | |
369 | try (PrintWriter writer = new PrintWriter(profileFile)) { | |
370 | writer.println("This file is created by JUnit test using " + LTTngToolsFileShell.class.getCanonicalName()); | |
371 | writer.println("Can be deleted!"); | |
372 | writer.close(); | |
373 | } | |
374 | } | |
375 | fProfileFile = profileFile; | |
376 | } | |
377 | } | |
378 | ||
379 | public void setProfileName(String profileName) { | |
380 | fProfileName = profileName; | |
381 | } | |
382 | ||
383 | public void deleteProfileFile() { | |
384 | if (fProfileFile != null && fProfileFile.exists()) { | |
385 | fProfileFile.delete(); | |
386 | } | |
387 | } | |
388 | ||
921151cf BH |
389 | public void setSessionName(String sessionName) { |
390 | fSessionName = sessionName; | |
391 | } | |
392 | ||
3d09f0a5 | 393 | |
d132bcc7 | 394 | } |