1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 08:55:25 +02:00

Bug 422797 - API for retrieving QMake information from Qt project

Adding a new IQMakeInfo getter:
* getQMakeQueryMap()
* getQtDocPath()
* getResourceFiles()
* getFormFiles()

Fixing incorrect parsing of OTHER_FILES variable.

Adding QMakeTests.testQMakeInfo() JUnit test for qmake output parser.

Change-Id: Ic4e0180381967e2a96455d6a3411fe51ce1cef91
Signed-off-by: David Kaspar <dkaspar@blackberry.com>
Reviewed-on: https://git.eclipse.org/r/20500
Reviewed-by: Doug Schaefer <dschaefer@qnx.com>
IP-Clean: Doug Schaefer <dschaefer@qnx.com>
Tested-by: Doug Schaefer <dschaefer@qnx.com>
This commit is contained in:
David Kaspar 2014-01-10 22:20:17 +01:00 committed by Doug Schaefer
parent e9b3224eaa
commit 5927d7ea30
6 changed files with 131 additions and 53 deletions

View file

@ -10,7 +10,8 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.expressions;bundle-version="[3.2.0,4.0.0)",
org.eclipse.cdt.core,
org.eclipse.cdt.codan.core,
org.eclipse.cdt.codan.core.cxx
org.eclipse.cdt.codan.core.cxx,
org.eclipse.core.filesystem
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin

View file

@ -35,37 +35,47 @@ public final class QMakeInfo implements IQMakeInfo {
/**
* Instance that is used to present an invalid IQMakeInfo.
*/
public static final IQMakeInfo INVALID = new QMakeInfo(
false, null, Collections.<String>emptyList(), Collections.<String>emptyList(),
Collections.<String>emptyList(), Collections.<String>emptyList(), Collections.<String>emptyList(),
Collections.<String>emptyList(), Collections.<String>emptyList(), Collections.<String>emptyList());
public static final IQMakeInfo INVALID = new QMakeInfo(false, Collections.<String,String>emptyMap(), Collections.<String,String>emptyMap());
private final boolean valid;
private final Map<String, String> qmakeQueryMap;
private final IQtVersion qtVersion;
private final List<String> involvedQMakeFiles;
private final List<String> qtImportPath;
private final List<String> qtQmlPath;
private final List<String> qtDocPath;
private final List<String> includePath;
private final List<String> defines;
private final List<String> sourceFiles;
private final List<String> headerFiles;
private final List<String> resourceFiles;
private final List<String> formFiles;
private final List<String> otherFiles;
private QMakeInfo(boolean valid, IQtVersion qtVersion, List<String> involvedQMakeFiles, List<String> qtImportPath, List<String> qtQmlPath, List<String> includePath, List<String> defines, List<String> sourceFiles, List<String> headerFiles, List<String> otherFiles) {
public QMakeInfo(boolean valid, Map<String,String> queryMap, Map<String,String> proMap) {
this.valid = valid;
this.qtVersion = qtVersion;
this.involvedQMakeFiles = Collections.unmodifiableList(involvedQMakeFiles);
this.qtImportPath = Collections.unmodifiableList(qtImportPath);
this.qtQmlPath = Collections.unmodifiableList(qtQmlPath);
this.includePath = Collections.unmodifiableList(includePath);
this.defines = Collections.unmodifiableList(defines);
this.sourceFiles = Collections.unmodifiableList(sourceFiles);
this.headerFiles = Collections.unmodifiableList(headerFiles);
this.otherFiles = Collections.unmodifiableList(otherFiles);
}
this.qmakeQueryMap = Collections.unmodifiableMap(queryMap);
public static IQMakeInfo create(File projectFile, File qmake, String[] extraEnv) {
return create(projectFile.getAbsolutePath(), qmake.getAbsolutePath(), extraEnv);
this.qtVersion = QMakeVersion.create(queryMap.get(QMakeParser.KEY_QT_VERSION));
List<String> tmpQtImportPaths = new ArrayList<String>(QMakeParser.singleValue(queryMap, QMakeParser.KEY_QT_INSTALL_IMPORTS));
List<String> tmpQtQmlPaths = new ArrayList<String>(QMakeParser.singleValue(queryMap, QMakeParser.KEY_QT_INSTALL_QML));
this.qtDocPath = QMakeParser.singleValue(queryMap, QMakeParser.KEY_QT_INSTALL_DOCS);
this.involvedQMakeFiles = QMakeParser.qmake3DecodeValueList(proMap, QMakeParser.KEY_QMAKE_INTERNAL_INCLUDED_FILES);
this.includePath = QMakeParser.qmake3DecodeValueList(proMap, QMakeParser.KEY_INCLUDEPATH);
this.defines = QMakeParser.qmake3DecodeValueList(proMap, QMakeParser.KEY_DEFINES);
this.sourceFiles = QMakeParser.qmake3DecodeValueList(proMap, QMakeParser.KEY_SOURCES);
this.headerFiles = QMakeParser.qmake3DecodeValueList(proMap, QMakeParser.KEY_HEADERS);
this.resourceFiles = QMakeParser.qmake3DecodeValueList(proMap, QMakeParser.KEY_RESOURCES);
this.formFiles = QMakeParser.qmake3DecodeValueList(proMap, QMakeParser.KEY_FORMS);
this.otherFiles = QMakeParser.qmake3DecodeValueList(proMap, QMakeParser.KEY_OTHER_FILES);
// combine qtImportPath and qtQmlPath from both qmake runs
List<String> qmlImportPath = QMakeParser.qmake3DecodeValueList(proMap, QMakeParser.KEY_QML_IMPORT_PATH);
tmpQtImportPaths.addAll(qmlImportPath);
tmpQtQmlPaths.addAll(qmlImportPath);
this.qtImportPath = Collections.unmodifiableList(tmpQtImportPaths);
this.qtQmlPath = Collections.unmodifiableList(tmpQtQmlPaths);
}
public static IQMakeInfo create(String proPath, String qmakePath, String[] extraEnv) {
@ -75,35 +85,17 @@ public final class QMakeInfo implements IQMakeInfo {
// run "qmake -query"
Map<String, String> qmake1 = exec(PATTERN_QUERY_LINE, extraEnv, qmakePath, "-query");
if (qmake1 == null)
if (qmake1 == null) {
return INVALID;
}
// check the qmake version
// check the qmake version
QMakeVersion version = QMakeVersion.create(qmake1.get(QMakeParser.KEY_QMAKE_VERSION));
// TODO - no support for pre-3.0
// for QMake version 3.0 or newer, run "qmake -E file.pro"
Map<String, String> qmake2 = version != null && version.getMajor() >= 3 ? exec(PATTERN_EVAL_LINE, extraEnv, qmakePath, "-E", proPath) : Collections.<String,String>emptyMap();
IQtVersion qtVersion = QMakeVersion.create(qmake1.get(QMakeParser.KEY_QT_VERSION));
List<String> qtImportPaths = QMakeParser.singleValue(qmake1, QMakeParser.KEY_QT_INSTALL_IMPORTS);
List<String> qtQmlPaths = QMakeParser.singleValue(qmake1, QMakeParser.KEY_QT_INSTALL_QML);
List<String> involvedQMakeFiles = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_QMAKE_INTERNAL_INCLUDED_FILES);
List<String> includePath = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_INCLUDEPATH);
List<String> defines = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_DEFINES);
List<String> sourceFiles = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_SOURCES);
List<String> headerFiles = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_HEADERS);
List<String> otherFiles = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_HEADERS);
List<String> qmlImportPath = QMakeParser.qmake3DecodeValueList(qmake2, QMakeParser.KEY_QML_IMPORT_PATH);
// combine qtImportPath and qtQmlPath from both qmake runs
List<String> realQtImportPaths = new ArrayList<String>(qtImportPaths);
realQtImportPaths.addAll(qmlImportPath);
List<String> realQtQmlPaths = new ArrayList<String>(qtQmlPaths);
realQtQmlPaths.addAll(qmlImportPath);
return new QMakeInfo(true, qtVersion, involvedQMakeFiles, realQtImportPaths, realQtQmlPaths, includePath, defines, sourceFiles, headerFiles, otherFiles);
return new QMakeInfo(true, qmake1, qmake2);
}
@Override
@ -111,9 +103,14 @@ public final class QMakeInfo implements IQMakeInfo {
return valid;
}
@Override
public Map<String, String> getQMakeQueryMap() {
return qmakeQueryMap;
}
@Override
public IQtVersion getQtVersion() {
return qtVersion;
return qtVersion;
}
@Override
@ -131,6 +128,11 @@ public final class QMakeInfo implements IQMakeInfo {
return qtQmlPath;
}
@Override
public List<String> getQtDocPath() {
return qtDocPath;
}
@Override
public List<String> getIncludePath() {
return includePath;
@ -152,9 +154,19 @@ public final class QMakeInfo implements IQMakeInfo {
}
@Override
public List<String> getOtherFiles() {
public List<String> getResourceFiles() {
return resourceFiles;
}
@Override
public List<String> getFormFiles() {
return formFiles;
}
@Override
public List<String> getOtherFiles() {
return otherFiles;
}
}
/**
* Executes a command and parses its output into a map.
@ -164,7 +176,6 @@ public final class QMakeInfo implements IQMakeInfo {
* @param cmd the command line
* @return the map of resolved key-value pairs
*/
@SuppressWarnings("resource")
private static Map<String, String> exec(Pattern regex, String[] extraEnv, String...command) {
if (command.length < 1 || ! new File(command[0]).exists()) {
QtPlugin.log("qmake: cannot run command: " + (command.length > 0 ? command[0] : ""));

View file

@ -28,11 +28,15 @@ public final class QMakeParser {
public static final String KEY_QT_VERSION = "QT_VERSION";
public static final String KEY_QT_INSTALL_IMPORTS = "QT_INSTALL_IMPORTS";
public static final String KEY_QT_INSTALL_QML = "QT_INSTALL_QML";
public static final String KEY_QT_INSTALL_DOCS = "QT_INSTALL_DOCS";
public static final String KEY_QMAKE_INTERNAL_INCLUDED_FILES = "QMAKE_INTERNAL_INCLUDED_FILES";
public static final String KEY_SOURCES = "SOURCES";
public static final String KEY_HEADERS = "HEADERS";
public static final String KEY_INCLUDEPATH = "INCLUDEPATH";
public static final String KEY_DEFINES = "DEFINES";
public static final String KEY_RESOURCES = "RESOURCES";
public static final String KEY_FORMS = "FORMS";
public static final String KEY_OTHER_FILES = "OTHER_FILES";
public static final String KEY_QML_IMPORT_PATH = "QML_IMPORT_PATH";
/**
@ -40,7 +44,7 @@ public final class QMakeParser {
*
* @param regex the reg. exp.
* @param reader the QMake output
* @return the map of parsed key-value pairs
* @return the modifiable map of parsed key-value pairs
* @throws IOException when io error happens
*/
public static Map<String, String> parse(Pattern regex, BufferedReader reader) throws IOException {
@ -64,11 +68,11 @@ public final class QMakeParser {
}
/**
* Returns a list with 0-1 values for a specific QMake variable.
* Returns an unmodifiable list with 0-1 values for a specific QMake variable.
*
* @param map the map
* @param key the QMake variable
* @return the list of values
* @return the unmodifiable list of values
*/
public static List<String> singleValue(Map<String, String> map, String key) {
String value = map.get(key);
@ -76,11 +80,11 @@ public final class QMakeParser {
}
/**
* Returns a list of values for a specific QMake variable that is decoded as a list of values.
* Returns an unmodifiable list of values for a specific QMake variable that is decoded as a list of values.
*
* @param map the map
* @param key the QMake variable
* @return the list of values
* @return the unmodifiable list of values
*/
public static List<String> qmake3DecodeValueList(Map<String, String> map, String key) {
String value = map.get(key);
@ -92,7 +96,7 @@ public final class QMakeParser {
for (String item : qmake3SplitValueList(value)) {
result.add(qmake3DecodeValue(item));
}
return result;
return Collections.unmodifiableList(result);
}
/**
@ -151,7 +155,7 @@ public final class QMakeParser {
* Splits a specified QMake variable value into a list of values.
*
* @param value the value
* @return the list of values
* @return the modifiable list of values
*/
private static List<String> qmake3SplitValueList(String value) {
List<String> result = new ArrayList<String>();

View file

@ -31,6 +31,7 @@ import org.eclipse.cdt.qt.core.index.IQMakeProjectInfo;
import org.eclipse.cdt.qt.core.index.IQMakeProjectInfoListener;
import org.eclipse.cdt.qt.core.index.QMakeEnvInfo;
import org.eclipse.cdt.qt.core.index.IQMakeInfo;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
@ -410,10 +411,12 @@ public final class QMakeProjectInfo implements IQMakeProjectInfo, ICProjectDescr
private static final class SensitiveSet extends HashSet<IPath> {
private static final long serialVersionUID = 2684086006933209512L;
// adds a sensitive file in form of a specified absolute path
private void addSensitiveFile(String sensitiveFile) {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IFile[] files = root.findFilesForLocation(Path.fromOSString(sensitiveFile));
IFile[] files = root.findFilesForLocationURI(URIUtil.toURI(Path.fromOSString(sensitiveFile).makeAbsolute()));
if (files != null && files.length > 0) {
IFile file = files[0];
addSensitiveFile(file);

View file

@ -8,6 +8,7 @@
package org.eclipse.cdt.qt.core.index;
import java.util.List;
import java.util.Map;
/**
* Represents a QMake information.
@ -25,6 +26,13 @@ public interface IQMakeInfo {
*/
boolean isValid();
/**
* Returns a map of key-value pairs provided by "qmake -query" command.
*
* @return the map
*/
Map<String,String> getQMakeQueryMap();
/**
* Returns a Qt version as provided by "qmake -query" command.
*
@ -54,6 +62,13 @@ public interface IQMakeInfo {
*/
List<String> getQtQmlPath();
/**
* Returns a list of Qt Documentation paths.
*
* @return the list of Qt Documentation paths
*/
List<String> getQtDocPath();
/**
* Returns a list of include paths that are used for compilation of a related project.
*
@ -82,6 +97,20 @@ public interface IQMakeInfo {
*/
List<String> getHeaderFiles();
/**
* Returns a list of resource file paths i.e. specified via RESOURCES QMake variable.
*
* @return the list of other file paths
*/
List<String> getResourceFiles();
/**
* Returns a list of other file paths i.e. specified via FORMS QMake variable.
*
* @return the list of other file paths
*/
List<String> getFormFiles();
/**
* Returns a list of other file paths i.e. specified via OTHER_FILES QMake variable.
*

View file

@ -9,6 +9,7 @@ package org.eclipse.cdt.qt.tests;
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -17,6 +18,7 @@ import junit.framework.TestCase;
import org.eclipse.cdt.internal.qt.core.index.QMakeInfo;
import org.eclipse.cdt.internal.qt.core.index.QMakeParser;
import org.eclipse.cdt.internal.qt.core.index.QMakeVersion;
import org.eclipse.cdt.qt.core.index.IQMakeInfo;
public class QMakeTests extends TestCase {
@ -40,7 +42,7 @@ public class QMakeTests extends TestCase {
assertEquals(0, three_dot_zero.getMinor());
}
public void testQMakeInfo() throws Exception {
public void testQMake3Decoder() throws Exception {
StringReader content = new StringReader("A = \\\\\\\"\nB = A\\n\\tB\nC = \"A \\\" B\" \"A \\\" B\"");
BufferedReader reader = new BufferedReader(content);
@ -64,4 +66,32 @@ public class QMakeTests extends TestCase {
assertEquals(0, D.size());
}
public void testQMakeInfo() throws Exception {
StringReader qmake1Content = new StringReader("QMAKE_VERSION:3.0\nQT_VERSION:5.2\nQT_INSTALL_IMPORTS:QtImports\nQT_INSTALL_QML:QtQmls\nQT_INSTALL_DOCS:QtDocs\nCustomKey:CustomValue\n");
BufferedReader qmake1Reader = new BufferedReader(qmake1Content);
Map<String, String> qmake1 = QMakeParser.parse(QMakeInfo.PATTERN_QUERY_LINE, qmake1Reader);
StringReader qmake2Content = new StringReader("QMAKE_INTERNAL_INCLUDED_FILES=Internal1 Internal2\nSOURCES=Source1 Source2\nHEADERS=Header1 Header2\nINCLUDEPATH=Include1 Include2\nDEFINES=Def1 Def2\nRESOURCES=Resource1 Resource2\nFORMS=Form1 Form2\nOTHER_FILES=Other1 Other2\nQML_IMPORT_PATH=CustomImport\n");
BufferedReader qmake2Reader = new BufferedReader(qmake2Content);
Map<String, String> qmake2 = QMakeParser.parse(QMakeInfo.PATTERN_EVAL_LINE, qmake2Reader);
IQMakeInfo info = new QMakeInfo(true, qmake1, qmake2);
assertNotNull(info);
assertEquals(5, info.getQtVersion().getMajor());
assertEquals(2, info.getQtVersion().getMinor());
assertEquals(Arrays.asList("QtImports", "CustomImport"), info.getQtImportPath());
assertEquals(Arrays.asList("QtQmls", "CustomImport"), info.getQtQmlPath());
assertEquals(Arrays.asList("QtDocs"), info.getQtDocPath());
assertEquals("CustomValue", info.getQMakeQueryMap().get("CustomKey"));
assertEquals(Arrays.asList("Include1", "Include2"), info.getIncludePath());
assertEquals(Arrays.asList("Def1", "Def2"), info.getDefines());
assertEquals(Arrays.asList("Header1", "Header2"), info.getHeaderFiles());
assertEquals(Arrays.asList("Source1", "Source2"), info.getSourceFiles());
assertEquals(Arrays.asList("Resource1", "Resource2"), info.getResourceFiles());
assertEquals(Arrays.asList("Form1", "Form2"), info.getFormFiles());
assertEquals(Arrays.asList("Other1", "Other2"), info.getOtherFiles());
}
}