/*******************************************************************************
* Copyright (c) 2014 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat - initial API and implementation
*******************************************************************************/
package org.eclipse.linuxtools.internal.systemtap.ui.ide.structures.tparsers;
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.linuxtools.internal.systemtap.ui.ide.structures.Messages;
/**
* A helper class for performing tapset-loading operations,
* and sharing the results with other {@link TapsetParser}s.
* Note that class this does not implement {@link ITreeParser},
* as no front-end operations are performed.
*/
public final class SharedParser extends TapsetParser {
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$
/**
* 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.
*/
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;
private static SharedParser parser = null;
public static SharedParser getInstance(){
if (parser != null) {
return parser;
}
parser = new SharedParser();
return parser;
}
private SharedParser() {
super(Messages.SharedParser_name);
}
/**
* Clear the cached tapset contents, so that the next call to {@link #getTapsetContents()}
* will be guaranteed to use a new call of stap to gather up-to-date tapset contents.
*/
public synchronized void clearTapsetContents() {
tapsetContents = null;
}
/**
* Get the contents of default & all imported tapsets. When calling this method
* for the first time (or after changing the list of tapset directories), this will
* run a dummy stap script to obtain the tapset contents, which will be cached into
* memory. Subsequent calls will simply read the saved contents.
* @return The string contents of tapsets, or <code>null</code> if there was an
* error in obtaining this information, or an empty string if the operation was cancelled.
*/
synchronized String getTapsetContents() {
return tapsetContents != null ? tapsetContents : runAction();
}
@Override
protected IStatus run(IProgressMonitor monitor) {
return createStatus(verifyRunResult(runAction()));
}
private String runAction() {
String contents = runStap(STAP_OPTIONS, STAP_DUMMYPROBE, false);
if (verifyRunResult(contents) == IStatus.OK) {
// 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).
int firstTagIndex = contents.indexOf(TAG_FILE);
if (firstTagIndex != -1) {
int beginIndex = contents.indexOf(TAG_FILE, firstTagIndex + 1);
if (beginIndex != -1) {
tapsetContents = contents.substring(beginIndex);
}
}
return tapsetContents;
}
return contents;
}
}