diff options
author | Vasili Gulevich | 2016-06-09 11:52:55 +0000 |
---|---|---|
committer | Vasili Gulevich | 2016-06-09 11:52:55 +0000 |
commit | cc1a900a37e6f3b298eeb4ff6317b552dbcede86 (patch) | |
tree | efd929e0ce7fe8bc2f07b829c94855acc1ca9788 | |
parent | 9b285550c2423056e56c94b1551f2f0ed417cb7b (diff) | |
download | org.eclipse.dltk.core-cc1a900a37e6f3b298eeb4ff6317b552dbcede86.tar.gz org.eclipse.dltk.core-cc1a900a37e6f3b298eeb4ff6317b552dbcede86.tar.xz org.eclipse.dltk.core-cc1a900a37e6f3b298eeb4ff6317b552dbcede86.zip |
Implemented optional encoding support for external libraries.
Fixed non-container external buildpath.
Signed-off-by: Vasili Gulevich <vasili.gulevich@xored.com>
Change-Id: I9840e234ffa7b1dc690c48f462b47096b8fd2123
12 files changed, 533 insertions, 42 deletions
diff --git a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/BuildpathEntry.java b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/BuildpathEntry.java index 8f4eaf662..e49b5313a 100644 --- a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/BuildpathEntry.java +++ b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/BuildpathEntry.java @@ -638,11 +638,16 @@ public class BuildpathEntry implements IBuildpathEntry { break; case IBuildpathEntry.BPE_LIBRARY: if (isExternal) { - String environmentId = EnvironmentManager - .getEnvironmentId(project.getProject()); - if (environmentId != null) { - path = EnvironmentPathUtils - .getFullPath(environmentId, path); + IPath fullPath = Path.fromPortableString(pathAttr); + if (!EnvironmentPathUtils.isFull(fullPath)) { + String environmentId = EnvironmentManager + .getEnvironmentId(project.getProject()); + if (environmentId != null) { + path = EnvironmentPathUtils + .getFullPath(environmentId, path); + } + } else { + path = fullPath; } } entry = DLTKCore.newLibraryEntry(path, accessRules, diff --git a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalEntryFile.java b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalEntryFile.java index 13817e362..48d62b241 100644 --- a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalEntryFile.java +++ b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalEntryFile.java @@ -15,6 +15,7 @@ import java.io.InputStream; import org.eclipse.core.resources.IStorage; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.PlatformObject; import org.eclipse.dltk.core.IModelStatusConstants; import org.eclipse.dltk.core.ModelException; @@ -29,6 +30,8 @@ public class ExternalEntryFile extends PlatformObject implements IStorage { private IFileHandle file; public ExternalEntryFile(IFileHandle file) { + if (file == null) + throw new NullPointerException(); this.file = file; } @@ -60,4 +63,12 @@ public class ExternalEntryFile extends PlatformObject implements IStorage { public String toString() { return "ExternalEntryFile[" + this.file.toOSString() + "]"; //$NON-NLS-2$ //$NON-NLS-1$ } + + @Override + public <T> T getAdapter(Class<T> adapter) { + T rv = super.getAdapter(adapter); + if (rv != null) + return rv; + return Platform.getAdapterManager().getAdapter(file, adapter); + } } diff --git a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalFoldersManager.java b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalFoldersManager.java index fba108723..10e70b166 100644 --- a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalFoldersManager.java +++ b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalFoldersManager.java @@ -71,7 +71,8 @@ public class ExternalFoldersManager { public static boolean isExternalFolderPath(IPath externalPath) { if (externalPath == null) return false; - if (ResourcesPlugin.getWorkspace().getRoot() + if (externalPath.segmentCount() > 0 + && ResourcesPlugin.getWorkspace().getRoot() .getProject(externalPath.segment(0)).exists()) return false; File externalFolder = externalPath.toFile(); diff --git a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalSourceModule.java b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalSourceModule.java index 2179ee7f4..36ab72b65 100644 --- a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalSourceModule.java +++ b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ExternalSourceModule.java @@ -7,9 +7,9 @@ ******************************************************************************/ package org.eclipse.dltk.internal.core; -import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.Charset; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IStorage; @@ -87,40 +87,36 @@ public class ExternalSourceModule extends AbstractExternalSourceModule { protected char[] getBufferContent() throws ModelException { IPath path = getBufferPath(); IFileHandle file = EnvironmentPathUtils.getFile(path); - + Charset charset = storage.getAdapter(Charset.class); IProjectFragment projectFragment = this.getProjectFragment(); - if (file != null && file.exists() && !projectFragment.isArchive()) { - return org.eclipse.dltk.internal.core.util.Util - .getResourceContentsAsCharArray(file); - } else { - if (projectFragment.isArchive()) { - final InputStream stream; - PerformanceNode p = RuntimePerformanceMonitor.begin(); - try { - stream = new BufferedInputStream(storage.getContents(), - 4096); - } catch (CoreException e) { - throw new ModelException(e, - IModelStatusConstants.ELEMENT_DOES_NOT_EXIST); - } + if (charset == null) { + if (projectFragment.isArchive()) + charset = Charset.forName(Util.UTF_8); + } + PerformanceNode p = RuntimePerformanceMonitor.begin(); + long length = 0; + try { + try { + InputStream stream = null; try { - char[] data = Util.getInputStreamAsCharArray(stream, -1, - Util.UTF_8); - p.done("#", RuntimePerformanceMonitor.IOREAD, data.length); - return data; - } catch (IOException e) { - throw new ModelException(e, - IModelStatusConstants.IO_EXCEPTION); + stream = storage.getContents(); + char[] rv = Util.getInputStreamAsCharArray(stream, -1, + charset == null ? null : charset.name()); + length = rv.length; + return rv; } finally { - try { + if (stream != null) stream.close(); - } catch (IOException e) { - // ignore - } } + } catch (CoreException e) { + throw new ModelException(e, + IModelStatusConstants.ELEMENT_DOES_NOT_EXIST); } + } catch (IOException e) { + throw new ModelException(e, IModelStatusConstants.IO_EXCEPTION); + } finally { + p.done("#", RuntimePerformanceMonitor.IOREAD, length); } - throw newNotPresentException(); } /** diff --git a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ScriptProject.java b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ScriptProject.java index 1a37571df..3e8dade06 100644 --- a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ScriptProject.java +++ b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/ScriptProject.java @@ -677,7 +677,8 @@ public class ScriptProject extends Openable implements IScriptProject, break; } if (checkExistency) { - if (entryPath.segment(0).startsWith( + if (entryPath.segmentCount() > 0 + && entryPath.segment(0).startsWith( IBuildpathEntry.BUILTIN_EXTERNAL_ENTRY_STR) && BuiltinProjectFragment.isSupported(this)) { root = new BuiltinProjectFragment(entryPath, this); diff --git a/core/tests/org.eclipse.dltk.core.tests/plugin.xml b/core/tests/org.eclipse.dltk.core.tests/plugin.xml index a660e0ccd..712122e80 100644 --- a/core/tests/org.eclipse.dltk.core.tests/plugin.xml +++ b/core/tests/org.eclipse.dltk.core.tests/plugin.xml @@ -95,5 +95,13 @@ class="org.eclipse.dltk.core.tests.cache.TestContentCacheProvider"> </contentCacheProvider> </extension> + <extension + point="org.eclipse.dltk.core.environment"> + <environment + class="org.eclipse.dltk.core.tests.util.EnvironmentProvider" + id="org.eclipse.dltk.core.tests.environment1" + priority="0"> + </environment> + </extension> </plugin> diff --git a/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/AllTests.java b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/AllTests.java index ff7f9497a..08a26693b 100644 --- a/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/AllTests.java +++ b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/AllTests.java @@ -9,10 +9,6 @@ *******************************************************************************/ package org.eclipse.dltk.core.tests; -import junit.framework.JUnit4TestAdapter; -import junit.framework.Test; -import junit.framework.TestSuite; - import org.eclipse.dltk.core.tests.builder.BuildParticipantManagerTests; import org.eclipse.dltk.core.tests.buildpath.BuildpathTests; import org.eclipse.dltk.core.tests.buildpath.SetContainerEventsTest; @@ -26,6 +22,7 @@ import org.eclipse.dltk.core.tests.launching.InterpreterConfigTests; import org.eclipse.dltk.core.tests.mixin.MixinIndexTests; import org.eclipse.dltk.core.tests.mixin.MixinModelTests; import org.eclipse.dltk.core.tests.model.BufferTests; +import org.eclipse.dltk.core.tests.model.ExternalFragmentTests; import org.eclipse.dltk.core.tests.model.ModelMembersTests; import org.eclipse.dltk.core.tests.model.NamespaceTests; import org.eclipse.dltk.core.tests.model.WorkingCopyTests; @@ -37,6 +34,10 @@ import org.eclipse.dltk.core.tests.utils.IntListTests; import org.eclipse.dltk.core.tests.utils.InternalCoreUtilTest; import org.eclipse.dltk.core.tests.utils.TextUtilsTest; +import junit.framework.JUnit4TestAdapter; +import junit.framework.Test; +import junit.framework.TestSuite; + public class AllTests { public static Test suite() { @@ -65,6 +66,7 @@ public class AllTests { suite.addTest(ModelMembersTests.suite()); suite.addTestSuite(NamespaceTests.class); suite.addTest(WorkingCopyTests.suite()); + suite.addTestSuite(ExternalFragmentTests.class); suite.addTest(new TestSuite(SourceParserTests.class)); diff --git a/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/AbstractModelTests.java b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/AbstractModelTests.java index e54cdc6af..d96dadc60 100644 --- a/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/AbstractModelTests.java +++ b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/AbstractModelTests.java @@ -302,8 +302,8 @@ public abstract class AbstractModelTests extends SuiteOfTestCases { if (project == null) { return null; } - IPath path = new Path(fragmentPath); - if (path.isAbsolute()) { + IPath path = Path.fromPortableString(fragmentPath); + if (path.isAbsolute() && path.getDevice() == null) { IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace() .getRoot(); IResource resource = workspaceRoot.findMember(path); @@ -318,10 +318,15 @@ public abstract class AbstractModelTests extends SuiteOfTestCases { } for (int i = 0; i < roots.length; i++) { IProjectFragment root = roots[i]; - if (root.getUnderlyingResource().getProjectRelativePath() + IResource underlyingResource = root.getUnderlyingResource(); + if (underlyingResource != null && underlyingResource + .getProjectRelativePath() .equals(path)) { return root; } + if (root.getPath().equals(path)) { + return root; + } } } return null; diff --git a/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/ExternalFragmentTests.java b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/ExternalFragmentTests.java new file mode 100644 index 000000000..f00cf5ed5 --- /dev/null +++ b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/ExternalFragmentTests.java @@ -0,0 +1,382 @@ +package org.eclipse.dltk.core.tests.model; + +import java.io.ByteArrayInputStream; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.dltk.compiler.util.Util; +import org.eclipse.dltk.core.ISourceModule; +import org.eclipse.dltk.core.ModelException; +import org.eclipse.dltk.core.environment.EnvironmentPathUtils; +import org.eclipse.dltk.core.environment.IEnvironment; +import org.eclipse.dltk.core.environment.IFileHandle; +import org.eclipse.dltk.core.tests.util.EnvironmentProvider; +import org.junit.Assert; + +public class ExternalFragmentTests extends AbstractModelTests { + private static final String PRJ_NAME = "Environment1"; + + public ExternalFragmentTests(String name) { + super(ModelTestsPlugin.PLUGIN_NAME, name); + } + + @Override + public void setUp() throws Exception { + super.setUpSuite(); + setUpScriptProjectTo(PRJ_NAME, "Environment1"); + } + + @Override + public void tearDown() throws Exception { + deleteProject(PRJ_NAME); + super.tearDownSuite(); + } + + private static class AbstractFileHandle implements IFileHandle { + + private final IEnvironment environment; + private final IPath path; + + public AbstractFileHandle(IEnvironment environment, IPath path) { + if (environment == null) + throw new NullPointerException(); + if (path == null) + throw new NullPointerException(); + this.environment = environment; + if (path.isAbsolute()) + throw new IllegalArgumentException(); + this.path = path; + } + + @Override + public IEnvironment getEnvironment() { + return environment; + } + + @Override + public String getEnvironmentId() { + return getEnvironment().getId(); + } + + @Override + public IPath getPath() { + return path; + } + + @Override + public String toOSString() { + return null; + } + + @Override + public String getCanonicalPath() { + return environment.getCanonicalPath(path); + } + + @Override + public IPath getFullPath() { + return EnvironmentPathUtils.getFullPath(getEnvironmentId(), path); + } + + @Override + public String getName() { + return path.lastSegment(); + } + + @Override + public URI toURI() { + return environment.getURI(path); + } + + @Override + public IFileHandle getParent() { + if (path.isEmpty()) + return null; + return getEnvironment().getFile(path.removeLastSegments(1)); + } + + @Override + public IFileHandle[] getChildren() { + return null; + } + + @Override + public IFileHandle getChild(String path) { + return null; + } + + @Override + public boolean exists() { + return true; + } + + @Override + public InputStream openInputStream(IProgressMonitor monitor) + throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public OutputStream openOutputStream(IProgressMonitor monitor) + throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isSymlink() { + return false; + } + + @Override + public boolean isDirectory() { + return false; + } + + @Override + public boolean isFile() { + return true; + } + + @Override + public long lastModified() { + return 0; + } + + @Override + public long length() { + return 0; + } + + @Override + public void move(IFileHandle destination) throws CoreException { + throw new UnsupportedOperationException(); + } + + } + + public static class FolderHandle extends AbstractFileHandle { + + private final Collection<String> children = new ArrayList<String>(); + + public FolderHandle(IEnvironment environment, IPath path) { + super(environment, path); + if (children == null) + throw new NullPointerException(); + } + + @Override + public boolean isDirectory() { + return true; + } + + @Override + public IFileHandle[] getChildren() { + ArrayList<IFileHandle> rv = new ArrayList<IFileHandle>(); + for (String name : children) + rv.add(getEnvironment().getFile(getPath().append(name))); + return rv.toArray(new IFileHandle[0]); + } + + @Override + public IFileHandle getChild(String path) { + return getEnvironment().getFile(getPath().append(path)); + } + + public void addChild(String name) { + children.add(name); + } + + + } + + public static class FileHandle extends AbstractFileHandle { + static { + Platform.getAdapterManager() + .registerAdapters(new IAdapterFactory() { + + @Override + public Class<?>[] getAdapterList() { + return new Class<?>[] { Charset.class }; + } + + @Override + public <T> T getAdapter(Object adaptableObject, + Class<T> adapterType) { + FileHandle file = (FileHandle) adaptableObject; + if (adapterType.isAssignableFrom(Charset.class)) { + return adapterType.cast(file.getCharset()); + } + return null; + } + }, FileHandle.class); + } + + private final byte[] content; + private final Charset charset; + + public FileHandle(IEnvironment environment, IPath path, + byte[] content, Charset charset) { + super(environment, path); + this.content = content; + this.charset = charset; + } + + protected Charset getCharset() { + return charset; + } + + @Override + public InputStream openInputStream(IProgressMonitor monitor) + throws IOException { + return new ByteArrayInputStream(content); + } + + @Override + public long length() { + return content.length; + } + + } + + + class Environment extends PlatformObject implements IEnvironment { + private final Map<IPath, IFileHandle> files = new HashMap<IPath, IFileHandle>(); + + @Override + public boolean isLocal() { + return false; + } + + @Override + public IFileHandle getFile(final IPath path) { + return files.get(path.makeRelative()); + } + + @Override + public String getId() { + return "testEnv"; + } + + @Override + public String getSeparator() { + return "" + IPath.SEPARATOR; + } + + @Override + public char getSeparatorChar() { + return IPath.SEPARATOR; + } + + @Override + public String getPathsSeparator() { + return ":"; + } + + @Override + public char getPathsSeparatorChar() { + return ':'; + } + + @Override + public String getName() { + return "Test environment"; + } + + @Override + public String convertPathToString(IPath path) { + return path.toPortableString(); + } + + @Override + public URI getURI(IPath location) { + try { + return new URI(getId(), location.toPortableString(), null); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + @Override + public IFileHandle getFile(URI locationURI) { + return getFile(Path + .fromPortableString(locationURI.getSchemeSpecificPart())); + } + + @Override + public String getCanonicalPath(IPath path) { + return path.toPortableString(); + } + + @Override + public boolean isConnected() { + return true; + } + + @Override + public boolean connect() { + return true; + } + + private FolderHandle getFolder(IPath path) { + IFileHandle folder = files.get(path); + if (folder instanceof FolderHandle) + return (FolderHandle) folder; + if (folder == null) { + FolderHandle nfolder = new FolderHandle(this, path); + put(nfolder); + return nfolder; + } + return null; + } + + public void put(IFileHandle fileHandle) { + IPath path = fileHandle.getPath(); + files.put(path, fileHandle); + if (!path.isEmpty()) + getFolder(path.removeLastSegments(1)) + .addChild(path.lastSegment()); + } + + } + + public void testWindowsLocale() throws ModelException, IOException { + Charset charset = Charset.forName("windows-1251"); + checkCharsetFlow(charset, "Русский текст1"); + } + + public void testUtfLocale() throws ModelException, IOException { + Charset charset = Charset.forName(Util.UTF_8); + checkCharsetFlow(charset, "Русский текст2"); + } + + private void checkCharsetFlow(Charset charset, String content) + throws ModelException, IOException { + Environment env = new Environment(); + Path path = new Path("X.txt"); + env.put(new FileHandle(env, path, content.getBytes(charset), charset)); + Closeable environmentUnsetter = EnvironmentProvider.setEnvironment(env); + try { + ISourceModule module = getSourceModule(PRJ_NAME, "testEnv/:/", + path); + Assert.assertEquals(content, module.getSource()); + } finally { + environmentUnsetter.close(); + } + } +} diff --git a/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/util/EnvironmentProvider.java b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/util/EnvironmentProvider.java new file mode 100644 index 000000000..668e4eb33 --- /dev/null +++ b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/util/EnvironmentProvider.java @@ -0,0 +1,66 @@ +package org.eclipse.dltk.core.tests.util; + +import java.io.Closeable; +import java.io.IOException; +import java.net.URI; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.resources.IProject; +import org.eclipse.dltk.core.environment.IEnvironment; +import org.eclipse.dltk.core.environment.IEnvironmentProvider; + +public class EnvironmentProvider implements IEnvironmentProvider { + + public static Map<String, IEnvironment> environments = Collections + .synchronizedMap(new HashMap<String, IEnvironment>()); + + public EnvironmentProvider() { + } + + @Override + public String getProviderName() { + return "Test environment provider"; + } + + @Override + public IEnvironment[] getEnvironments() { + return environments.keySet().toArray(new IEnvironment[0]); + } + + @Override + public IEnvironment getEnvironment(String envId) { + return environments.get(envId); + } + + @Override + public boolean isInitialized() { + return true; + } + + @Override + public void waitInitialized() { + } + + @Override + public IEnvironment getProjectEnvironment(IProject project) { + return null; + } + + @Override + public IEnvironment getEnvironment(URI locationURI) { + return environments.get(locationURI.getScheme()); + } + + public static Closeable setEnvironment(final IEnvironment environment) { + final String id = environment.getId(); + environments.put(id, environment); + return new Closeable() { + @Override + public void close() throws IOException { + environments.remove(id); + } + }; + } +} diff --git a/core/tests/org.eclipse.dltk.core.tests/workspace/Environment1/.buildpath b/core/tests/org.eclipse.dltk.core.tests/workspace/Environment1/.buildpath new file mode 100644 index 000000000..7934698f4 --- /dev/null +++ b/core/tests/org.eclipse.dltk.core.tests/workspace/Environment1/.buildpath @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<buildpath> + <buildpathentry external="true" kind="lib" path="testEnv/:/"/> +</buildpath> diff --git a/core/tests/org.eclipse.dltk.core.tests/workspace/Environment1/.project b/core/tests/org.eclipse.dltk.core.tests/workspace/Environment1/.project new file mode 100644 index 000000000..6272d911d --- /dev/null +++ b/core/tests/org.eclipse.dltk.core.tests/workspace/Environment1/.project @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>p1</name> + <comment></comment> + <projects> + </projects> + <natures> + <nature>org.eclipse.dltk.core.tests.testnature</nature> + </natures> +</projectDescription> |