use of org.eclipse.n4js.projectModel.IN4JSProject in project n4js by eclipse.
the class TestDiscoveryHelper method isTestable.
/**
* Checks if the resource at the given location can be executed as a test. The location may point to an N4JS project
* or a folder or file within an N4JS project.
* <p>
* This method is intended as a very first check to decide if the user should be given the option to launch a test
* or not; for example, to enable or disable a "Run as test" context menu item). This method does not check all
* details because many checks are better handled at later stages when meaningful error messages can be provided to
* the user.
*/
public boolean isTestable(final URI location) {
if (null == location) {
return false;
}
if (isProject(location)) {
// location points an N4JS project
// --> must contain at least 1 source container of type "test"
// (do *not* check if the folder contains test classes (for performance reasons and
// to show better error messages; same behavior as in JUnit support in Eclipse))
final IN4JSProject p = n4jsCore.create(location);
return p.getSourceContainers().stream().anyMatch(IN4JSSourceContainer::isTest);
} else {
// then extract the fragment and check the location for the module.
if (location.hasFragment()) {
return isTestable(location.trimFragment());
}
// (2) location must lie in a source container of type "test"
final IN4JSSourceContainer c = n4jsCore.findN4JSSourceContainer(location).orNull();
if (c == null || !c.isTest())
return false;
// (3) if the location points to an n4js-file, it must contain at least one test class
final ResourceSet resourceSet = n4jsCore.createResourceSet(Optional.of(c.getProject()));
final IResourceDescriptions index = n4jsCore.getXtextIndex(resourceSet);
final IResourceDescription rdesc = index.getResourceDescription(location);
if (rdesc != null) {
return stream(rdesc.getExportedObjectsByType(T_CLASS)).anyMatch(desc -> hasTestMethods(resourceSet, desc));
} else {
// to show better error messages; same behavior as in JUnit support in Eclipse))
return true;
}
}
}
use of org.eclipse.n4js.projectModel.IN4JSProject in project n4js by eclipse.
the class RunnerFileBasedShippedCodeConfigurationHelper method configureFromFileSystem.
/**
* Reconfigures provided run configuration in regards of {@link RunConfiguration#getExecModule()},
* {@link RunConfiguration#getInitModules()} and {@link RunConfiguration#getCoreProjectPaths()} by plain using file
* system access to the shipped code. Intended to be used in situations where proper workspace setup is not
* available and run configurations created by default are lacking essential information.
*
* It is up to the caller to decide when it is appropriate to call this method.
*
* @param config
* the configuration to be reconfigured.
*/
public void configureFromFileSystem(RunConfiguration config) {
Iterable<IN4JSProject> allShippedProjects = RunnerN4JSCore.getAllShippedProjects();
IN4JSProject customRuntimeEnvironment = getCustomRuntimeEnvironment(config, allShippedProjects);
reconfigure(config, allShippedProjects, customRuntimeEnvironment);
}
use of org.eclipse.n4js.projectModel.IN4JSProject in project n4js by eclipse.
the class RunnerHelper method getProjectExtendedDepsAndApiImplMapping.
/**
* Returns a mapping from all API projects among <code>dependencies</code> to their corresponding implementation
* project for implementation ID <code>implementationId</code>.
* <p>
* Special cases: if there are no API projects among the dependencies, this method will return an empty map in
* {@link ApiUsage#concreteApiImplProjectMapping} and {@link ApiUsage#implementationIdRequired}<code>==false</code>;
* otherwise, if <code>implementationId</code> is <code>null</code>, then this method will assert that there exists
* exactly one implementation for the API projects among the dependencies and use that (stored in
* {@link ApiUsage#implementationId}).
* <p>
* Throws exception in case of error given <code>throwOnError==true</code>, never returns null.
*
* @param runtimeEnvironment
* active runtime environment.
* @param moduleToRun
* what to run.
* @param implementationId
* might be <code>null</code>
* @param throwOnError
* if true fast fail in erroneous situations. Otherwise tries to proceed in a meaningful way. State can
* then be queried on the ApiUsage instance.
*
* @return result wrapped in an {@link ApiUsage} instance.
*/
// TODO this methods could require some cleanup after the concepts of API-Implementation mappings stabilized...
public ApiUsage getProjectExtendedDepsAndApiImplMapping(RuntimeEnvironment runtimeEnvironment, URI moduleToRun, String implementationId, boolean throwOnError) {
final LinkedHashSet<IN4JSProject> deps = new LinkedHashSet<>();
// 1) add project containing the moduleToRun and its direct AND indirect dependencies
final Optional<? extends IN4JSProject> project = n4jsCore.findProject(moduleToRun);
if (project.isPresent() == false) {
throw new RuntimeException("can't obtain containing project for moduleToRun: " + moduleToRun);
}
recursiveDependencyCollector(project.get(), deps, new RecursionGuard<>());
// TODO need to add not only REs but also RLs they provide
// 2) add the runtime environment project, REs it extends and RLs provided
final Optional<IN4JSProject> reProject = getCustomRuntimeEnvironmentProject(runtimeEnvironment);
if (reProject.isPresent()) {
IN4JSProject re = reProject.get();
recursiveExtendedREsCollector(re, deps);
} else {
// IDE-1359: don't throw exception to make runners work without user-defined runtime environment
// (will be changed later when library manager is available!)
// throw new RuntimeException("can't obtain runtime environment project for " + moduleToRun2);
}
// TODO actually we would like to return the dependencies in load order:
// - RuntimeEnvironment boot
// - all RuntimeLibrary boots (take deps2 between RLs into account)
// - all other deps2 (order does not matter they just needs to be on path later)
// - project to be called
// maybe some in order DFS or something above?
// manually transform to list, or is this one ok?
final ApiImplMapping apiImplMapping = ApiImplMapping.of(deps, n4jsCore.findAllProjects());
if (apiImplMapping.hasErrors()) {
if (throwOnError)
throw new IllegalStateException("the workspace setup contains errors related to API / implementation projects (check manifests of related projects):\n " + Joiner.on("\n ").join(apiImplMapping.getErrorMessages()));
}
if (apiImplMapping.isEmpty()) {
return ApiUsage.of(new ArrayList<>(deps), Collections.<IN4JSProject, IN4JSProject>emptyMap(), apiImplMapping);
}
// there must be exactly one implementation for the API projects in the workspace
if (implementationId == null) {
final List<String> allImplIds = apiImplMapping.getAllImplIds();
if (allImplIds.size() != 1) {
if (throwOnError) {
throw new IllegalStateException("no implementationId specified while several are available in the workspace: " + allImplIds);
} else {
// back out, further processing not possible without implementations id.
return ApiUsage.of(new ArrayList<>(deps), Collections.emptyMap(), apiImplMapping, true);
}
} else {
implementationId = allImplIds.get(0);
}
}
final Map<IN4JSProject, IN4JSProject> apiImplProjectMapping = new LinkedHashMap<>();
// projectIds of projects without an implementation
final List<String> missing = new ArrayList<>();
for (IN4JSProject dep : deps) {
if (dep != null) {
final String depId = dep.getProjectId();
if (depId != null && apiImplMapping.isApi(depId)) {
// so: dep is an API project ...
final IN4JSProject impl = apiImplMapping.getImpl(depId, implementationId);
if (impl != null) {
// so: impl is the implementation project for dep for implementation ID 'implementationId'
apiImplProjectMapping.put(dep, impl);
} else {
// bad: no implementation for dep for implementation ID 'implementationId'
missing.add(depId);
}
}
}
}
if (!missing.isEmpty()) {
if (throwOnError) {
throw new IllegalStateException("no implementation for implementation ID \"" + implementationId + "\" found for the following projects: " + Joiner.on(", ").join(missing));
}
}
// / #-#-#-#-#-#-#-#-#-#-#-#-#-#-#
// IDEBUG-506 look for additional dependencies, pulled in from api-impl project not yet processed:
HashSet<IN4JSProject> processedDepProjects = deps;
LinkedHashSet<IN4JSProject> tobeInspectedApiImplProjects = new LinkedHashSet<>();
apiImplProjectMapping.entrySet().forEach(p -> {
IN4JSProject v = p.getValue();
if (!processedDepProjects.contains(v))
tobeInspectedApiImplProjects.add(v);
});
// Collect transitive mappings. Populate with original ones.
final Map<IN4JSProject, IN4JSProject> joinedApiImplProjectMapping = new LinkedHashMap<>(apiImplProjectMapping);
while (!tobeInspectedApiImplProjects.isEmpty()) {
// compute dependencies if necessary
LinkedHashSet<IN4JSProject> batchedPivotDependencies = new LinkedHashSet<>();
RecursionGuard<URI> guard = new RecursionGuard<>();
for (IN4JSProject pivotProject : tobeInspectedApiImplProjects) {
recursiveDependencyCollector(pivotProject, batchedPivotDependencies, guard);
}
tobeInspectedApiImplProjects.clear();
List<IN4JSProject> batchedPivotNewDepList = batchedPivotDependencies.stream().filter(p -> null != p && !processedDepProjects.contains(p)).collect(Collectors.toList());
// new Api-mapping
apiImplMapping.enhance(batchedPivotNewDepList, n4jsCore.findAllProjects());
// go over new dependencies and decide:
for (IN4JSProject pivNewDep : batchedPivotNewDepList) {
final String depId = pivNewDep.getProjectId();
if (apiImplMapping.isApi(depId)) {
// API-mapping
if (joinedApiImplProjectMapping.containsKey(pivNewDep)) {
// already done.
} else {
// put new entry
IN4JSProject pivImpl = apiImplMapping.getImpl(depId, implementationId);
if (null != pivImpl) {
joinedApiImplProjectMapping.put(pivNewDep, pivImpl);
tobeInspectedApiImplProjects.add(pivImpl);
} else {
missing.add(depId);
}
}
} else {
// no API.
if (!processedDepProjects.contains(pivNewDep)) {
// add to deps
processedDepProjects.add(pivNewDep);
}
}
}
}
if (!missing.isEmpty()) {
if (throwOnError) {
throw new IllegalStateException("no implementation for implementation ID \"" + implementationId + "\" found for the following projects: " + Joiner.on(", ").join(missing));
}
}
return ApiUsage.of(implementationId, new ArrayList<>(deps), apiImplProjectMapping, apiImplMapping, missing);
}
use of org.eclipse.n4js.projectModel.IN4JSProject in project n4js by eclipse.
the class RunnerN4JSCore method getAllShippedProjects.
/**
* Returns all shipped projects as iterable. Returned projects are stubs for real {@link N4JSProject}. They
* implement the same API only to allow common utilities to calculate runner information for both real workspace
* based projects and stubs returned here. All information is calculated from the file system on the fly, and is not
* stored. Subsequent calls will result all information being computed once more.
*
* @return iterable of shipped code wrapped in {@link IN4JSProject} interface
*/
public static Iterable<IN4JSProject> getAllShippedProjects() {
final RunnerTargetPlatformInstallLocationProvider locationProvider = new RunnerTargetPlatformInstallLocationProvider();
final RunnerClasspathPackageManager manager = new RunnerClasspathPackageManager();
final RunnerExternalLibraryWorkspace workspace = new RunnerExternalLibraryWorkspace(manager);
final N4JSModel model = new N4JSModel(workspace, locationProvider);
ShippedCodeAccess.getAllShippedPaths().forEach(path -> discoveProjects(path, workspace));
// we need to collect projects provided by the workspace iterator into iterable instance to allow caller to make
// multiple iterations over it. Note that just wrapping iterator into iterable (e.g. via
// org.eclipse.xtext.xbase.lib.IteratorExtensions) does not work, i.e. it is just simple wrapping that allows
// one iteration just like plain iterator.
List<IN4JSProject> projects = new ArrayList<>();
workspace.getAllProjectsLocations().forEachRemaining(location -> projects.add(model.getN4JSProject(location)));
return projects;
}
use of org.eclipse.n4js.projectModel.IN4JSProject in project n4js by eclipse.
the class RuntimeEnvironmentsHelper method recursiveCompatibleEnvironemntCollector.
/**
* recursively searches given source container for provided runtime environments
*/
private void recursiveCompatibleEnvironemntCollector(IN4JSSourceContainerAware sourceContainer, Collection<String> collection, Predicate<IN4JSProject> predicate, List<IN4JSProject> allRuntimeEnv) {
IN4JSProject project = (extractProject(sourceContainer));
if (predicate.test(project)) {
com.google.common.base.Optional<String> oExtendedProjectId = project.getExtendedRuntimeEnvironmentId();
if (!oExtendedProjectId.isPresent()) {
return;
}
String extendedProjectId = oExtendedProjectId.get();
collection.add(extendedProjectId);
allRuntimeEnv.stream().filter(p -> p.getProjectId().equals(extendedProjectId)).findFirst().ifPresent(exre -> recursiveCompatibleEnvironemntCollector(exre, collection, predicate, allRuntimeEnv));
}
}
Aggregations