Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Ferrazzutti2014-07-22 15:07:31 +0000
committerJeff Johnston2014-08-15 22:29:00 +0000
commit74a99f1c9f3ee6aba26a31063a0ee23a8d2f5cb3 (patch)
treebc4e6e8404c8973233150ad0d567f6fb50a5b784 /systemtap
parent931bda546c3e30a7a42f24ca2c810479cfe98662 (diff)
downloadorg.eclipse.linuxtools-74a99f1c9f3ee6aba26a31063a0ee23a8d2f5cb3.tar.gz
org.eclipse.linuxtools-74a99f1c9f3ee6aba26a31063a0ee23a8d2f5cb3.tar.xz
org.eclipse.linuxtools-74a99f1c9f3ee6aba26a31063a0ee23a8d2f5cb3.zip
Systemtap: Implement selective tapset loading.
When the list of imported tapsets is changed (with Preferences->SystemTap->IDE->Tapsets), instead of triggering a new tapset load operation to re-load all tapset contents, only load in the newly-added tapsets and delete the ones that were removed. Change-Id: I3dac162704f2bee5fc30217c3578a098c66aa724 Signed-off-by: Andrew Ferrazzutti <aferrazz@redhat.com> Reviewed-on: https://git.eclipse.org/r/31464 Tested-by: Hudson CI Reviewed-by: Jeff Johnston <jjohnstn@redhat.com> Tested-by: Jeff Johnston <jjohnstn@redhat.com>
Diffstat (limited to 'systemtap')
-rw-r--r--systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/FunctionParser.java151
-rw-r--r--systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/Messages.java4
-rw-r--r--systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/ProbeParser.java230
-rw-r--r--systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/SharedParser.java48
-rw-r--r--systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TapsetLibrary.java26
-rw-r--r--systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TapsetParser.java27
-rw-r--r--systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TreeTapsetParser.java89
-rw-r--r--systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/messages.properties4
8 files changed, 442 insertions, 137 deletions
diff --git a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/FunctionParser.java b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/FunctionParser.java
index 3e1ca26c87..3e325220dc 100644
--- a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/FunctionParser.java
+++ b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/FunctionParser.java
@@ -45,7 +45,7 @@ public final class FunctionParser extends TreeTapsetParser {
private static final Pattern P_FUNCTION = Pattern.compile("function (?!_)(\\w+) \\(.*?\\)"); //$NON-NLS-1$
private static final Pattern P_PARAM = Pattern.compile("(\\w+)(?:\\s*:\\s*(\\w+))?"); //$NON-NLS-1$
private static final Pattern P_ALL_CAP = Pattern.compile("[A-Z_1-9]*"); //$NON-NLS-1$
- private static final Pattern P_RETURN = Pattern.compile("\\sreturn\\W"); //$NON-NLS-1$
+ private static final Pattern P_RETURN = Pattern.compile("(?<!\\w)return\\W"); //$NON-NLS-1$
public static FunctionParser getInstance() {
if (parser != null) {
@@ -56,16 +56,7 @@ public final class FunctionParser extends TreeTapsetParser {
}
private FunctionParser() {
- super("Function Parser"); //$NON-NLS-1$
- }
-
- /**
- * Runs stap to collect all available tapset functions.
- */
- @Override
- protected IStatus runAction(IProgressMonitor monitor) {
- addFunctions(monitor);
- return super.runAction(monitor);
+ super(Messages.FunctionParser_name);
}
/**
@@ -74,58 +65,68 @@ public final class FunctionParser extends TreeTapsetParser {
*
* FunctionTree organized as:
* Root->Functions->Parameters
- *
- * @return <code>false</code> if a cancelation prevented all functions from being added;
- * <code>true</code> otherwise.
*/
- private boolean addFunctions(IProgressMonitor monitor) {
+ @Override
+ protected int runAction(IProgressMonitor monitor) {
if (monitor.isCanceled()) {
- return false;
+ return IStatus.CANCEL;
}
String tapsetContents = SharedParser.getInstance().getTapsetContents();
- if (tapsetContents == null) {
- // Functions are only drawn from the tapset dump, so exit if it's empty.
- return true;
+ int result = verifyRunResult(tapsetContents);
+ if (result != IStatus.OK) {
+ return result;
}
boolean canceled = false;
- try (Scanner st = new Scanner(tapsetContents)) {
- String filename = null;
- String scriptText = null;
-
- SharedParser sparser = SharedParser.getInstance();
- while (st.hasNextLine()) {
+ try (Scanner scanner = new Scanner(tapsetContents)) {
+ scanner.useDelimiter("(?=" + SharedParser.TAG_FILE + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ while (scanner.hasNext()) {
if (monitor.isCanceled()) {
canceled = true;
break;
}
- String tok = st.nextLine();
- Matcher mFilename = sparser.filePattern.matcher(tok);
- if (mFilename.matches()) {
- filename = mFilename.group(1).toString();
- scriptText = null;
- } else if (filename != null) {
- Matcher mFunction = P_FUNCTION.matcher(tok);
- if (mFunction.matches()) {
- String functionName = mFunction.group(1);
- if (P_ALL_CAP.matcher(functionName).matches()) {
- // Ignore ALL_CAPS functions, since they are not meant for end-user use.
- continue;
- }
- if (scriptText == null) {
- // If this is the first time seeing this file, remove its comments.
- scriptText = CommentRemover.execWithFile(filename);
- }
- addFunctionFromScript(functionName, scriptText, filename);
- }
- }
+ addFunctionsFromFileContents(scanner.next());
+ }
+ }
+ tree.sortLevel();
+ return !canceled ? IStatus.OK : IStatus.CANCEL;
+ }
+
+ /**
+ * Uses the tapset content dump of a single file to collect all
+ * functions provided by that file.
+ * @param fileContents The tapset contents of a single file.
+ */
+ private void addFunctionsFromFileContents(String fileContents) {
+ String filename;
+ try (Scanner st = new Scanner(fileContents)) {
+ filename = SharedParser.findFileNameInTag(st.nextLine());
+ }
+
+ Matcher matcher = P_FUNCTION.matcher(fileContents);
+ String scriptText = null;
+ while (matcher.find()) {
+ String functionName = matcher.group(1);
+ if (P_ALL_CAP.matcher(functionName).matches()) {
+ // Ignore ALL_CAPS functions, since they are not meant for end-user use.
+ continue;
}
+ if (scriptText == null) {
+ // If this is the first time seeing this file, remove its comments.
+ scriptText = CommentRemover.execWithFile(filename);
+ }
+ addFunctionFromScript(functionName, scriptText, filename);
}
- tree.sortTree();
- return !canceled;
}
+ /**
+ * Searches the actual contents of a .stp script file for a specific function, and adds
+ * @param functionName The name of the function to search for.
+ * @param scriptText The contents of the script to search, with its comments removed
+ * (Use {@link CommentRemover} on file contents before passing them here, if necessary).
+ * @param scriptFilename The name of the script file being searched.
+ */
private void addFunctionFromScript(String functionName, String scriptText, String scriptFilename) {
String regex = MessageFormat.format(FUNC_REGEX, functionName);
Matcher mScript = Pattern.compile(regex).matcher(scriptText);
@@ -134,7 +135,7 @@ public final class FunctionParser extends TreeTapsetParser {
String functionType = mScript.group(1);
// If the function has no return type, look for a "return" statement to check
// if it's really a void function, or if its return type is just unspecified
- if (functionType == null && getNextBlockContents(scriptText, mScript.end(), P_RETURN)) {
+ if (functionType == null && isPatternInScriptBlock(scriptText, mScript.end(), P_RETURN)) {
functionType = UNKNOWN_TYPE;
}
TreeDefinitionNode function = new TreeDefinitionNode(
@@ -145,7 +146,7 @@ public final class FunctionParser extends TreeTapsetParser {
}
}
- private boolean getNextBlockContents(String scriptText, int start, Pattern p) {
+ private boolean isPatternInScriptBlock(String scriptText, int start, Pattern p) {
int end, bcount = 1;
start = scriptText.indexOf('{', start) + 1;
for (end = start; end < scriptText.length(); end++) {
@@ -168,6 +169,58 @@ public final class FunctionParser extends TreeTapsetParser {
mParams.group(1), false));
}
}
+ parentFunction.sortLevel();
+ }
+
+ @Override
+ protected int delTapsets(String[] deletions, IProgressMonitor monitor) {
+ for (int i = 0; i < deletions.length; i++) {
+ for (int f = 0, fn = tree.getChildCount(); f < fn; f++) {
+ if (monitor.isCanceled()) {
+ return IStatus.CANCEL;
+ }
+ String definition = ((TreeDefinitionNode) tree.getChildAt(f)).getDefinition();
+ if (definition != null && definition.startsWith(deletions[i])) {
+ tree.remove(f--);
+ fn--;
+ }
+ }
+ }
+ return IStatus.OK;
+ }
+
+ @Override
+ protected int addTapsets(String[] additions, IProgressMonitor monitor) {
+ String tapsetContents = SharedParser.getInstance().getTapsetContents();
+ boolean canceled = false;
+
+ // Search tapset contents for all files provided by each added directory.
+ for (int i = 0; i < additions.length; i++) {
+ int firstTagIndex = 0;
+ while (true) {
+ // Get the contents of each file provided by the directory additions[i].
+ firstTagIndex = tapsetContents.indexOf(
+ SharedParser.makeFileTag(additions[i]), firstTagIndex);
+ if (firstTagIndex == -1) {
+ break;
+ }
+ int nextTagIndex = tapsetContents.indexOf(SharedParser.TAG_FILE, firstTagIndex + 1);
+ String fileContents = nextTagIndex != -1
+ ? tapsetContents.substring(firstTagIndex, nextTagIndex)
+ : tapsetContents.substring(firstTagIndex);
+
+ if (monitor.isCanceled()) {
+ canceled = true;
+ break;
+ }
+ addFunctionsFromFileContents(fileContents);
+ // Remove the contents of the file that was just examined from the total contents.
+ tapsetContents = tapsetContents.substring(0, firstTagIndex).concat(
+ tapsetContents.substring(firstTagIndex + fileContents.length()));
+ }
+ }
+ tree.sortLevel();
+ return !canceled ? IStatus.OK : IStatus.CANCEL;
}
}
diff --git a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/Messages.java b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/Messages.java
index 3ae0b62588..f1647a9700 100644
--- a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/Messages.java
+++ b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/Messages.java
@@ -17,6 +17,9 @@ import org.eclipse.osgi.util.NLS;
*/
public class Messages extends NLS {
private static final String BUNDLE_NAME = "org.eclipse.linuxtools.internal.systemtap.ui.ide.structures.messages"; //$NON-NLS-1$
+ public static String SharedParser_name;
+ public static String FunctionParser_name;
+ public static String ProbeParser_name;
public static String ProbeParser_errorInitializingStaticProbes;
public static String ProbeParser_staticProbes;
public static String ProbeParser_aliasProbes;
@@ -26,7 +29,6 @@ public class Messages extends NLS {
public static String TapsetParser_ErrorRunningSystemtap;
public static String TapsetParser_RemoteCredentialErrorTitle;
public static String TapsetParser_RemoteCredentialErrorMessage;
- public static String SharedParser_NoOutput;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/ProbeParser.java b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/ProbeParser.java
index c096d6f6a1..d2ab9fc06f 100644
--- a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/ProbeParser.java
+++ b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/ProbeParser.java
@@ -12,6 +12,9 @@
package org.eclipse.linuxtools.internal.systemtap.ui.ide.structures;
import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
@@ -36,6 +39,7 @@ public final class ProbeParser extends TreeTapsetParser {
public static final String PROBE_REGEX = "(?s)(?<!\\w)probe\\s+{0}\\s*\\+?="; //$NON-NLS-1$
private static final String TAPSET_PROBE_REGEX = "probe {0} \\+?="; //$NON-NLS-1$
+ private static final Pattern PROBE_GROUP_PATTERN = Pattern.compile("[^\\.\\( ]+"); //$NON-NLS-1$
private static ProbeParser parser = null;
public static ProbeParser getInstance(){
@@ -47,7 +51,7 @@ public final class ProbeParser extends TreeTapsetParser {
}
private ProbeParser() {
- super("Probe Parser"); //$NON-NLS-1$
+ super(Messages.ProbeParser_name);
}
/**
@@ -67,33 +71,34 @@ public final class ProbeParser extends TreeTapsetParser {
* Root->Named Groups->ProbePoints->Variables
*/
@Override
- protected IStatus runAction(IProgressMonitor monitor) {
- addStaticProbes(monitor);
- addProbeAliases(monitor, tree.getChildAt(0));
- return super.runAction(monitor);
+ protected int runAction(IProgressMonitor monitor) {
+ int result = addStaticProbes(monitor);
+ if (result == IStatus.OK) {
+ result = addProbeAliases(monitor);
+ }
+ return result;
}
/**
* Runs stap to obtain a log of all static probes, and populate the probe tree with them.
- *
- * @return <code>false</code> if a cancelation prevented all probes from being added;
- * <code>true</code> otherwise.
+ * @return An {@link IStatus} severity level for the result of the operation.
*/
- private boolean addStaticProbes(IProgressMonitor monitor) {
+ private int addStaticProbes(IProgressMonitor monitor) {
TreeNode statics = new TreeNode(Messages.ProbeParser_staticProbes, false);
tree.add(statics);
if (monitor.isCanceled()) {
- return false;
+ return IStatus.CANCEL;
}
String probeDump = runStap(new String[]{"--dump-probe-types"}, null, false); //$NON-NLS-1$
- if (probeDump == null) {
- return false;
+ int result = verifyRunResult(probeDump);
+ if (result != IStatus.OK) {
+ return result;
}
boolean canceled = false;
try (Scanner st = new Scanner(probeDump)) {
- TreeNode group = null;
+ TreeNode groupNode = null;
while (st.hasNextLine()) {
if (monitor.isCanceled()) {
canceled = true;
@@ -101,36 +106,39 @@ public final class ProbeParser extends TreeTapsetParser {
}
String tokenString = st.nextLine();
String probeName = (new StringTokenizer(tokenString)).nextToken();
- group = addOrFindProbeGroup(extractProbeGroupName(probeName), group, statics);
- group.add(makeStaticProbeNode(probeName));
+ groupNode = addOrFindProbeGroup(extractProbeGroupName(probeName), groupNode, statics);
+ groupNode.add(makeStaticProbeNode(probeName));
}
}
statics.sortTree();
- return !canceled;
+ return !canceled ? IStatus.OK : IStatus.CANCEL;
}
/**
* Runs stap to obtain a log of all probe aliases & their variables,
* and populate the probe tree with them.
- *
- * @return <code>false</code> if a cancelation prevented all probes from being added;
- * <code>true</code> otherwise.
+ * @return An {@link IStatus} severity level for the result of the operation.
*/
- private boolean addProbeAliases(IProgressMonitor monitor, TreeNode statics) {
+ private int addProbeAliases(IProgressMonitor monitor) {
+ TreeNode statics = tree.getChildByName(Messages.ProbeParser_staticProbes);
+ if (statics == null) {
+ return IStatus.ERROR;
+ }
TreeNode aliases = new TreeNode(Messages.ProbeParser_aliasProbes, false);
tree.add(aliases);
- if (statics == null || monitor.isCanceled()) {
- return false;
+ if (monitor.isCanceled()) {
+ return IStatus.CANCEL;
}
String probeDump = runStap(new String[]{"-L"}, "**", false); //$NON-NLS-1$ //$NON-NLS-2$
- if (probeDump == null) {
- return false;
+ int result = verifyRunResult(probeDump);
+ if (result != IStatus.OK) {
+ return result;
}
boolean canceled = false;
try (Scanner st = new Scanner(probeDump)) {
- TreeNode group = null;
+ TreeNode groupNode = null;
while (st.hasNextLine()) {
if (monitor.isCanceled()) {
canceled = false;
@@ -142,35 +150,56 @@ public final class ProbeParser extends TreeTapsetParser {
if (tokenString.startsWith("_")) { //$NON-NLS-1$
continue;
}
-
- StringTokenizer probeTokenizer = new StringTokenizer(tokenString);
- String probeName = probeTokenizer.nextToken();
-
- String groupName = extractProbeGroupName(tokenString);
// Only add this group if it is not a static probe group
- if (statics.getChildByName(groupName) == null) {
- TreeNode probeNode = makeProbeAliasNode(probeName);
- group = addOrFindProbeGroup(groupName, group, aliases);
- group.add(probeNode);
- addAllVarNodesToProbeNode(probeTokenizer, probeNode);
+ String groupName = extractProbeGroupName(tokenString);
+ if (statics.getChildByName(groupName) != null) {
+ continue;
}
+ groupNode = addSingleProbeAlias(tokenString, aliases, groupNode, groupName, null);
}
}
aliases.sortTree();
- return !canceled;
+ return !canceled ? IStatus.OK : IStatus.CANCEL;
+ }
+
+ /**
+ * Adds a single probe alias to the collection.
+ * @param probeLine A line of probe information printed by a call to "stap -L".
+ * @param aliases The tree of probe aliases. The probe will be added to this tree.
+ * @param groupNode For optimization, pass an existing group node here, as it will be used if the
+ * probe belongs in it. Otherwise, or if <code>null</code> is passed, a new one will be created.
+ * @param groupName The name of the probe group, or <code>null</code> if it is unknown at the time
+ * this method is called.
+ * @param definition The path of the file in which this probe is defined, or <code>null</code> if it
+ * is unknown at the time this method is called.
+ */
+ private TreeNode addSingleProbeAlias(String probeLine, TreeNode aliases, TreeNode groupNode,
+ String groupName, String definition) {
+ StringTokenizer probeTokenizer = new StringTokenizer(probeLine);
+ String probeName = probeTokenizer.nextToken();
+
+ TreeNode probeNode = makeProbeAliasNode(probeName,
+ definition == null ? findDefinitionOf(probeName) : definition);
+
+ groupNode = addOrFindProbeGroup(
+ groupName == null ? extractProbeGroupName(probeName) : groupName,
+ groupNode, aliases);
+
+ groupNode.add(probeNode);
+ addAllVarNodesToProbeNode(probeTokenizer, probeNode);
+ return groupNode;
}
/**
- * Find the appropriate parent group node for a probe alias to group probes by name.
+ * Finds the appropriate parent group node for a probe alias to group probes by name.
* If it doesn't yet exist, create it and add it to the view's tree.
- * @param probeLine The name of the probe group.
+ * @param groupName The name of the probe group.
* @param groupNode For optimization, pass an existing group node here, as it will be
* used if the probe belongs in it. Otherwise, or if <code>null</code> is passed, a new one will be created.
* @param category The parent tree node in which to put the group node.
* @return The found or created group node that will be the parent of the probe's entry item in the view.
*/
private TreeNode addOrFindProbeGroup(String groupName, TreeNode groupNode, TreeNode category) {
-
// If the current probe belongs to a group other than
// the most recent group. This should rarely be needed because the
// probe list is sorted... mostly.
@@ -190,50 +219,38 @@ public final class ProbeParser extends TreeTapsetParser {
* @return the name of the group a probe belongs to, based on the probe's name.
*/
private String extractProbeGroupName(String probeName) {
- int dotIndex = probeName.indexOf('.');
- int parenIndex = probeName.indexOf('(');
- if (dotIndex > 0 && parenIndex > 0) {
- return probeName.substring(0, Math.min(dotIndex, parenIndex));
- }
- if (dotIndex > 0) {
- return probeName.substring(0, dotIndex);
- }
- if (parenIndex > 0) {
- return probeName.substring(0, parenIndex);
- }
- return probeName;
+ Matcher m = PROBE_GROUP_PATTERN.matcher(probeName);
+ return m.find() ? m.group() : probeName;
}
private TreeNode makeStaticProbeNode(String probeName) {
return new TreeNode(new ProbeNodeData(probeName), probeName, true);
}
- private TreeNode makeProbeAliasNode(String probeName) {
- return new TreeDefinitionNode(new ProbeNodeData(probeName), probeName, findDefinitionOf(probeName), true);
+ private TreeNode makeProbeAliasNode(String probeName, String definition) {
+ return new TreeDefinitionNode(new ProbeNodeData(probeName), probeName, definition, true);
}
/**
- * Search the tapset content dump for the path of the file which defines the provided probe alias.
+ * Searches the tapset content dump for the path of the file which defines the provided probe alias.
* @param probeName The alias of the probe to find the definition file of.
* @return The path of the probe's definition file, or <code>null</code> if a definition
* file can't be found (which is the case for static probes).
*/
private String findDefinitionOf(String probeName) {
- SharedParser sparser = SharedParser.getInstance();
- String tapsetContents = sparser.getTapsetContents();
+ String tapsetContents = SharedParser.getInstance().getTapsetContents();
if (tapsetContents == null) {
return null;
}
- Matcher probeMatcher = Pattern.compile(MessageFormat.format(TAPSET_PROBE_REGEX, Pattern.quote(probeName))).matcher(tapsetContents);
+ Matcher probeMatcher = Pattern.compile(MessageFormat.format(
+ TAPSET_PROBE_REGEX, Pattern.quote(probeName))).matcher(tapsetContents);
if (!probeMatcher.find()) {
return null;
}
- int fileLocIndex = tapsetContents.substring(0, probeMatcher.start()).lastIndexOf(SharedParser.TAG_FILE);
+ int fileLocIndex = tapsetContents.substring(0, probeMatcher.start())
+ .lastIndexOf(SharedParser.TAG_FILE);
try (Scanner scanner = new Scanner(tapsetContents.substring(fileLocIndex))) {
- Matcher fileMatcher = sparser.filePattern.matcher(scanner.nextLine());
- return fileMatcher.matches()
- ? fileMatcher.group(1)
- : null;
+ return SharedParser.findFileNameInTag(scanner.nextLine());
}
}
@@ -264,10 +281,99 @@ public final class ProbeParser extends TreeTapsetParser {
prev.setLength(prev.length() - 1); // Remove the trailing space.
addVarNodeToProbeNode(prev.toString(), probeNode);
}
+ probeNode.sortLevel();
}
private void addVarNodeToProbeNode(String info, TreeNode probeNode) {
probeNode.add(new TreeNode(new ProbevarNodeData(info), info, false));
}
+ @Override
+ protected int delTapsets(String[] tapsets, IProgressMonitor monitor) {
+ TreeNode aliases = tree.getChildByName(Messages.ProbeParser_aliasProbes);
+
+ // Search through alias groups for probes whose definition files
+ // come from removed directories, and remove them from the group.
+ for (int i = 0; i < tapsets.length; i++) {
+ for (int g = 0, gn = aliases.getChildCount(); g < gn; g++) {
+ if (monitor.isCanceled()) {
+ return IStatus.CANCEL;
+ }
+ TreeNode group = aliases.getChildAt(g);
+ for (int p = 0, pn = group.getChildCount(); p < pn; p++) {
+ String definition = ((TreeDefinitionNode) group.getChildAt(p)).getDefinition();
+ if (definition != null && definition.startsWith(tapsets[i])) {
+ group.remove(p--);
+ pn--;
+ }
+ }
+ // If removing the only probe left in a probe group, remove the group.
+ if (group.getChildCount() == 0) {
+ aliases.remove(g--);
+ gn--;
+ }
+ }
+ }
+ return IStatus.OK;
+ }
+
+ @Override
+ protected int addTapsets(String[] additions, IProgressMonitor monitor) {
+ String tapsetContents = SharedParser.getInstance().getTapsetContents();
+ boolean canceled = false;
+ TreeNode aliases = tree.getChildByName(Messages.ProbeParser_aliasProbes);
+ Map<String, ArrayList<String>> fileToItemMap = new HashMap<>();
+
+ // Search tapset contents for all files provided by each added directory.
+ for (int i = 0; i < additions.length; i++) {
+ int firstTagIndex = 0;
+ while (true) {
+ // Get the contents of each file provided by the directory additions[i].
+ firstTagIndex = tapsetContents.indexOf(
+ SharedParser.makeFileTag(additions[i]), firstTagIndex);
+ if (firstTagIndex == -1) {
+ break;
+ }
+ int nextTagIndex = tapsetContents.indexOf(SharedParser.TAG_FILE, firstTagIndex + 1);
+ String fileContents = nextTagIndex != -1
+ ? tapsetContents.substring(firstTagIndex, nextTagIndex)
+ : tapsetContents.substring(firstTagIndex);
+
+ String filename;
+ try (Scanner st = new Scanner(fileContents)) {
+ filename = SharedParser.findFileNameInTag(st.nextLine());
+ }
+
+ // Search file contents for the probes the file provides.
+ ArrayList<String> newItems = new ArrayList<>();
+ Matcher matcher = Pattern.compile(MessageFormat.format(
+ TAPSET_PROBE_REGEX, "(\\S+)")) //$NON-NLS-1$
+ .matcher(fileContents);
+ while (matcher.find()) {
+ newItems.add(matcher.group(1));
+ }
+ if (!newItems.isEmpty()) {
+ fileToItemMap.put(filename, newItems);
+ }
+ // Remove the contents of the file that was just examined from the total contents.
+ tapsetContents = tapsetContents.substring(0, firstTagIndex).concat(
+ tapsetContents.substring(firstTagIndex + fileContents.length()));
+ }
+ }
+ // Run stap on each discovered probe to obtain their variable information.
+ for (String file : fileToItemMap.keySet()) {
+ for (String newitem : fileToItemMap.get(file)) {
+ if (canceled || monitor.isCanceled()) {
+ canceled = true;
+ break;
+ }
+ addSingleProbeAlias(runStap(new String[]{"-L"}, newitem, false), //$NON-NLS-1$
+ aliases, null, null, file);
+ }
+ }
+
+ aliases.sortTree();
+ return !canceled ? IStatus.OK : IStatus.CANCEL;
+ }
+
}
diff --git a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/SharedParser.java b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/SharedParser.java
index 18e88f6f19..c845f28fff 100644
--- a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/SharedParser.java
+++ b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/SharedParser.java
@@ -11,12 +11,11 @@
package org.eclipse.linuxtools.internal.systemtap.ui.ide.structures;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.linuxtools.internal.systemtap.ui.ide.IDEPlugin;
/**
* A helper class for performing tapset-loading operations,
@@ -26,13 +25,43 @@ import org.eclipse.linuxtools.internal.systemtap.ui.ide.IDEPlugin;
*/
public final class SharedParser extends TapsetParser {
- static final String TAG_FILE = "# file"; //$NON-NLS-1$
private static final String[] STAP_OPTIONS = new String[] {"-v", "-p1", "-e"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
private static final String STAP_DUMMYPROBE = "probe begin{}"; //$NON-NLS-1$
+
+ /*
+ * Note: tapset content dumps (as printed by a pass 1 call of stap) list the contents
+ * of each script file found in all tapset directores. The contents of each file are
+ * prefaced/tagged with the line "# file <filename>", so contents of individual files
+ * can be found by searching the dump for such a tag.
+ */
+ /**
+ * The start of the tag that is always printed immediately before a file's contents in
+ * a tapset dump. Useful for searching through dumps for the contents of an individual file.
+ */
+ static final String TAG_FILE = "# file "; //$NON-NLS-1$
+ private static final Pattern FILE_PATTERN = Pattern.compile(TAG_FILE.concat("(/.*\\.stp)")); //$NON-NLS-1$
+
/**
- * A pattern that can be used to locate file paths listed in stap tapset dumps.
+ * Returns the entire tag that is printed immediately before a given file's contents in
+ * a tapset dump.
+ * @param fileName The name of the file (or a regex string) to get a tag for.
+ * @return The tag for the given file's contents as it appears in the tapset dump.
*/
- final Pattern filePattern = Pattern.compile("# file (/.*\\.stp)"); //$NON-NLS-1$
+ static String makeFileTag(String fileName) {
+ return TAG_FILE.concat(fileName);
+ }
+
+ /**
+ * Searches a string of tapset contents for a file tag and extracts the filename
+ * found in the tag.
+ * @param contents The tapset contents to search through. Preferably pass just a file tag
+ * here (generated by a call to {@linkplain #makeFileTag(String)}.
+ * @return The file name found.
+ */
+ static String findFileNameInTag(String contents) {
+ Matcher matcher = FILE_PATTERN.matcher(contents);
+ return matcher.find() ? matcher.group(1) : null;
+ }
private String tapsetContents = null;
@@ -46,7 +75,7 @@ public final class SharedParser extends TapsetParser {
}
private SharedParser() {
- super("Shared Parser"); //$NON-NLS-1$
+ super(Messages.SharedParser_name);
}
/**
@@ -75,8 +104,9 @@ public final class SharedParser extends TapsetParser {
@Override
protected IStatus run(IProgressMonitor monitor) {
String contents = runStap(STAP_OPTIONS, STAP_DUMMYPROBE, false);
- if (contents == null) {
- return new Status(IStatus.ERROR, IDEPlugin.PLUGIN_ID, Messages.SharedParser_NoOutput);
+ int result = verifyRunResult(contents);
+ if (result != IStatus.OK) {
+ return createStatus(result);
}
// Exclude the dump of the test script by excluding everything before the second pathname
// (which is the first actual tapset file, not the input script).
@@ -87,7 +117,7 @@ public final class SharedParser extends TapsetParser {
tapsetContents = contents.substring(beginIndex);
}
}
- return new Status(IStatus.OK, IDEPlugin.PLUGIN_ID, ""); //$NON-NLS-1$
+ return createStatus(IStatus.OK);
}
}
diff --git a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TapsetLibrary.java b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TapsetLibrary.java
index 1902b5d5ba..e3a96c7b83 100644
--- a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TapsetLibrary.java
+++ b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TapsetLibrary.java
@@ -12,6 +12,9 @@
package org.eclipse.linuxtools.internal.systemtap.ui.ide.structures;
import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
@@ -29,8 +32,6 @@ import org.eclipse.linuxtools.systemtap.ui.consolelog.internal.ConsoleLogPlugin;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
-
-
/**
* This class is used for obtaining all probes and functions from the tapsets.
* If stored tapsets are in use, it will try to obtain the list from the TreeSettings memento.
@@ -94,8 +95,9 @@ public final class TapsetLibrary {
@Override
public void propertyChange(PropertyChangeEvent event) {
String property = event.getProperty();
- if (property.equals(IDEPreferenceConstants.P_TAPSETS)
- || property.equals(PreferenceConstants.P_ENV.SYSTEMTAP_TAPSET.toPrefKey())
+ if (property.equals(IDEPreferenceConstants.P_TAPSETS)) {
+ applyTapsetChanges((String) event.getOldValue(), (String) event.getNewValue());
+ } else if (property.equals(PreferenceConstants.P_ENV.SYSTEMTAP_TAPSET.toPrefKey())
|| property.equals(IDEPreferenceConstants.P_REMOTE_PROBES)) {
runStapParser();
} else if (property.equals(IDEPreferenceConstants.P_STORED_TREE)) {
@@ -155,6 +157,22 @@ public final class TapsetLibrary {
probeParser.schedule();
}
+ private static void applyTapsetChanges(String oldTapsets, String newTapsets) {
+ List<String> oldList = Arrays.asList(oldTapsets.split(File.pathSeparator));
+ List<String> newList = Arrays.asList(newTapsets.split(File.pathSeparator));
+ List<String> additions = new ArrayList<>(newList);
+ additions.removeAll(oldList);
+ additions.remove(""); //$NON-NLS-1$
+ List<String> deletions = new ArrayList<>(oldList);
+ deletions.removeAll(newList);
+ deletions.remove(""); //$NON-NLS-1$
+ String[] additionArray = additions.toArray(new String[additions.size()]);
+ String[] deletionArray = deletions.toArray(new String[deletions.size()]);
+ SharedParser.getInstance().clearTapsetContents();
+ probeParser.runUpdate(additionArray, deletionArray);
+ functionParser.runUpdate(additionArray, deletionArray);
+ }
+
private static void clearTrees() {
if (functionTree != null) {
functionTree.dispose();
diff --git a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TapsetParser.java b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TapsetParser.java
index 59b73dbeab..efdfb9a31b 100644
--- a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TapsetParser.java
+++ b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TapsetParser.java
@@ -16,6 +16,8 @@ import java.io.IOException;
import java.net.ConnectException;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
@@ -65,6 +67,13 @@ public abstract class TapsetParser extends Job {
}
/**
+ * Generates a {@link Status} with the provided severity.
+ */
+ protected IStatus createStatus(int severity) {
+ return new Status(severity, IDEPlugin.PLUGIN_ID, ""); //$NON-NLS-1$
+ }
+
+ /**
* Runs stap with the given options and returns the output generated,
* or <code>null</code> if the case of an error.
* @param options String[] of any optional parameters to pass to stap
@@ -72,6 +81,8 @@ public abstract class TapsetParser extends Job {
* or <code>null</code> for scriptless commands
* @param getErrors Set this to <code>true</code> if the script's error
* stream contents should be returned instead of its standard output
+ * @return The output generated from the stap run, or <code>null</code>
+ * in the case of an error, or an empty string if the run was canceled.
*/
protected String runStap(String[] options, String probe, boolean getErrors) {
String[] args = null;
@@ -118,12 +129,26 @@ public abstract class TapsetParser extends Job {
} catch (IOException e) {
displayError(Messages.TapsetParser_ErrorRunningSystemtap, e.getMessage());
} catch (InterruptedException e) {
- // Interrupted; exit.
+ return ""; //$NON-NLS-1$
}
return null;
}
+ /**
+ * Return an {@link IStatus} severity constant for the result of a call to
+ * {@link TapsetParser#runStap(String[], String, boolean)}.
+ * @param result The output generated by a call to {@link #runStap(String[], String, boolean)}.
+ */
+ protected int verifyRunResult(String result) {
+ if (result == null) {
+ return IStatus.ERROR;
+ } else if (result.isEmpty()) {
+ return IStatus.CANCEL;
+ }
+ return IStatus.OK;
+ }
+
private String runLocalStap(String[] args, boolean getErrors) throws IOException, InterruptedException {
Process process = RuntimeProcessFactory.getFactory().exec(
args, EnvironmentVariablesPreferencePage.getEnvironmentVariables(), null);
diff --git a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TreeTapsetParser.java b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TreeTapsetParser.java
index e3b5f2ebe1..095c867f84 100644
--- a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TreeTapsetParser.java
+++ b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/TreeTapsetParser.java
@@ -13,8 +13,6 @@ package org.eclipse.linuxtools.internal.systemtap.ui.ide.structures;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.linuxtools.internal.systemtap.ui.ide.IDEPlugin;
import org.eclipse.linuxtools.systemtap.structures.TreeNode;
/**
@@ -23,8 +21,20 @@ import org.eclipse.linuxtools.systemtap.structures.TreeNode;
*/
public abstract class TreeTapsetParser extends TapsetParser {
+ private class TapsetChanges {
+ private String[] additions;
+ private String[] deletions;
+ private TapsetChanges(String[] additions, String[] deletions) {
+ this.additions = new String[additions.length];
+ this.deletions = new String[deletions.length];
+ System.arraycopy(additions, 0, this.additions, 0, additions.length);
+ System.arraycopy(deletions, 0, this.deletions, 0, deletions.length);
+ }
+ }
+
protected TreeNode tree = null;
private TreeNode forcedTree = null;
+ private TapsetChanges tapsetChanges = null;
protected TreeTapsetParser(String jobTitle) {
super(jobTitle);
@@ -37,21 +47,80 @@ public abstract class TreeTapsetParser extends TapsetParser {
@Override
protected final synchronized IStatus run(IProgressMonitor monitor) {
if (forcedTree != null) {
+ tapsetChanges = null;
tree = forcedTree;
forcedTree = null;
- return new Status(IStatus.OK, IDEPlugin.PLUGIN_ID, ""); //$NON-NLS-1$
- } else {
- tree = new TreeNode(null, false);
- return runAction(monitor);
+ return createStatus(IStatus.OK);
}
+ if (tapsetChanges != null) {
+ return performUpdate(monitor);
+ }
+ tree = new TreeNode(null, false);
+ return createStatus(runAction(monitor));
+ }
+
+ /**
+ * Loads the tapset contents and saves them.
+ * @param monitor The progress monitor for the operation.
+ * @return An {@link IStatus} severity level for the result of the operation.
+ */
+ protected abstract int runAction(IProgressMonitor monitor);
+
+ /**
+ * After adding / removing tapsets, scheduled the job that
+ * loads in / discards the tapsets that were added / removed.
+ * @param additions The list of added tapset directories.
+ * @param deletions The list of removed tapset directories.
+ */
+ public synchronized void runUpdate(String[] additions, String[] deletions) {
+ tapsetChanges = new TapsetChanges(additions, deletions);
+ schedule();
}
- protected IStatus runAction(IProgressMonitor monitor) {
- return new Status(!monitor.isCanceled() ? IStatus.OK : IStatus.CANCEL,
- IDEPlugin.PLUGIN_ID, ""); //$NON-NLS-1$
+ /**
+ * Performs both stages of a tapset update operation, ensuring that the new
+ * tapset contents will be available when they are necessary.
+ * @param monitor The operation's progress monitor.
+ * @return The status of the operation's outcome.
+ */
+ private IStatus performUpdate(IProgressMonitor monitor) {
+ int result = IStatus.OK;
+ if (tapsetChanges.deletions.length > 0) {
+ result = delTapsets(tapsetChanges.deletions, monitor);
+ }
+ if (result == IStatus.OK && tapsetChanges.additions.length > 0) {
+ if (monitor.isCanceled()) {
+ result = IStatus.CANCEL;
+ } else {
+ String tapsetContents = SharedParser.getInstance().getTapsetContents();
+ result = verifyRunResult(tapsetContents);
+ if (result == IStatus.OK) {
+ result = addTapsets(tapsetChanges.additions, monitor);
+ }
+ }
+ }
+ tapsetChanges = null;
+ return createStatus(result);
}
/**
+ * After changing the list of imported tapsets, discards the tapsets that were removed.
+ * @param deletions A non-empty list of removed tapset directories.
+ * @param monitor The progress monitor for the operation.
+ * @return An {@link IStatus} severity level for the result of the operation.
+ */
+ protected abstract int delTapsets(String[] deletions, IProgressMonitor monitor);
+
+ /**
+ * After changing the list of imported tapsets, loads in the tapsets that were added.
+ * Tapset contents are guaranteed to be loaded at the time this method is called.
+ * @param additions A non-empty list of added tapset directories.
+ * @param monitor The progress monitor for the operation.
+ * @return An {@link IStatus} severity level for the result of the operation.
+ */
+ protected abstract int addTapsets(String[] additions, IProgressMonitor monitor);
+
+ /**
* @return The tree that this parser constructs.
*/
public final synchronized TreeNode getTree() {
@@ -76,7 +145,7 @@ public abstract class TreeTapsetParser extends TapsetParser {
/**
* Check if the provided tree a valid tree for this parser.
* Called internally by {@link #setTree(TreeNode)}.
- * @param tree The tree to check for validity.
+ * @param tree The tree to check for validity.
* @return <code>null</code> if the tree is valid; otherwise,
* an error message signifying why the tree is invalid.
*/
diff --git a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/messages.properties b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/messages.properties
index 0a1e9dafeb..e5be6a7a6c 100644
--- a/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/messages.properties
+++ b/systemtap/org.eclipse.linuxtools.systemtap.ui.ide/src/org/eclipse/linuxtools/internal/systemtap/ui/ide/structures/messages.properties
@@ -9,6 +9,9 @@
# Red Hat - initial API and implementation
###############################################################################
+SharedParser_name=Preparation for tapset parsers
+FunctionParser_name=Function Parser
+ProbeParser_name=Probe Parser
ProbeParser_errorInitializingStaticProbes=Could not initialize static probe list
ProbeParser_staticProbes=Static Probes
ProbeParser_aliasProbes=Probe Aliases
@@ -18,4 +21,3 @@ TapsetParser_CannotRunStapTitle=Cannot Run SystemTap
TapsetParser_ErrorRunningSystemtap=Error Running SystemTap
TapsetParser_RemoteCredentialErrorTitle=Remote Login Error
TapsetParser_RemoteCredentialErrorMessage=Unable to login to the remote host for loading tapset contents. Edit the login credentials now?
-SharedParser_NoOutput=No stap output was generated \ No newline at end of file

Back to the top