use of org.eclipse.n4js.runner.extension.RuntimeEnvironment in project n4js by eclipse.
the class RunnerFrontEnd method configureRuntimeEnvironment.
/**
* Configures provided configuration based on the {@link RunConfiguration#getRuntimeEnvironment() runtime
* environment} value it stores.
*
* Recomputes {@link RunConfiguration#getInitModules() init modules} and {@link RunConfiguration#getExecModule()
* exec module} based on current state of the workspace.
*
* @param config
* the runtime configuration whose derived values are computed.
*/
public void configureRuntimeEnvironment(RunConfiguration config, Iterable<IN4JSProject> projects) {
RuntimeEnvironment runtimeEnvironment = config.getRuntimeEnvironment();
Optional<IN4JSProject> findRuntimeEnvironmentProject = hRuntimeEnvironments.findRuntimeEnvironmentProject(runtimeEnvironment, projects);
if (findRuntimeEnvironmentProject.isPresent()) {
IN4JSProject runtimeEnvironmentProject = findRuntimeEnvironmentProject.get();
// 3) collect custom(!) init modules based on selected runtime environment
final List<String> initModulePaths = getInitModulesPathsFrom(runtimeEnvironmentProject);
config.setInitModules(initModulePaths);
// 4) find compiled .js file to be executed first (the "executionModule" of the runtime environment)
Optional<String> executionModule = getExecModulePathFrom(runtimeEnvironmentProject);
if (executionModule.isPresent()) {
config.setExecModule(executionModule.get());
}
}
}
use of org.eclipse.n4js.runner.extension.RuntimeEnvironment in project n4js by eclipse.
the class RuntimeEnvironmentsHelper method recursiveCollectRlFromChain.
private void recursiveCollectRlFromChain(IN4JSProject runtimeEnvironment, Collection<IN4JSProject> collection) {
Optional<String> extended = runtimeEnvironment.getExtendedRuntimeEnvironmentId();
if (extended.isPresent()) {
String id = extended.get();
List<IN4JSProject> extendedRE = from(getAllProjects()).filter(p -> id.equals(p.getProjectId())).toList();
if (extendedRE.isEmpty()) {
return;
}
if (extendedRE.size() > 1) {
LOGGER.debug("multiple projects match id " + id);
LOGGER.error(new RuntimeException("Cannot obtain transitive list of provided libraries"));
return;
}
IN4JSProject extendedRuntimeEnvironemnt = extendedRE.get(0);
recursiveProvidedRuntimeLibrariesCollector(extendedRuntimeEnvironemnt.getProvidedRuntimeLibraries(), collection, p -> isRuntimeLibrary(p));
recursiveCollectRlFromChain(extendedRuntimeEnvironemnt, collection);
}
}
use of org.eclipse.n4js.runner.extension.RuntimeEnvironment in project n4js by eclipse.
the class RuntimeEnvironmentsHelper method containsAllCompatible.
/**
* Compares two provided lists of {@link IN4JSProject}. Assumes both contain instances of type
* {@link ProjectType#RUNTIME_ENVIRONMENT}. Checks if either all elements of latter list are contained in first one,
* or if all elements of latter one are compatible (are in extend chain) of elements of the first one. If this check
* holds returns true, otherwise false (also when either of the lists is empty)
*
* @param runnerEnvironments
* lists which must contain (might be indirectly via extend chain) elements of latter list
* @param requiredEnvironments
* lists that is checked if it is supported by first one
* @return true if all elements of latter list are (directly or indirectly) compatible with elements of the first
* list.
*/
public boolean containsAllCompatible(List<RuntimeEnvironment> runnerEnvironments, List<RuntimeEnvironment> requiredEnvironments) {
if (runnerEnvironments.isEmpty() || requiredEnvironments.isEmpty()) {
LOGGER.debug("cannot compare empty runtime environments lists");
return false;
}
if (runnerEnvironments.containsAll(requiredEnvironments))
return true;
// check compatible / extend feature
boolean result = true;
List<IN4JSProject> allRuntimeEnvironments = from(getAllProjects()).filter(p -> isRuntimeEnvironemnt(p)).toList();
Map<IN4JSProject, List<String>> reExtendedEnvironments = allRuntimeEnvironments.stream().map(re -> getExtendedRuntimeEnvironmentsNames(re, allRuntimeEnvironments)).collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
// if runnerEnvironments (first param) would be single IN4JSProject (instead of collection)
// code below could be simplified
Iterator<RuntimeEnvironment> iterRuntimeEnvironment = runnerEnvironments.iterator();
while (result && iterRuntimeEnvironment.hasNext()) {
RuntimeEnvironment re = iterRuntimeEnvironment.next();
List<IN4JSProject> listExtendedEnvironments = reExtendedEnvironments.keySet().stream().filter(p -> p.getProjectId().equals(re.getProjectId())).collect(Collectors.toList());
if (listExtendedEnvironments.size() != 1) {
LOGGER.debug("Multiple projects with name " + re.getProjectId() + " : " + listExtendedEnvironments.stream().map(p -> p.getProjectId()).reduce(new String(), (String r, String e) -> r += ", " + e));
LOGGER.error("Cannot obtain project for name " + re.getProjectId());
return false;
}
IN4JSProject extendedRuntimeEnvironment = listExtendedEnvironments.get(0);
List<String> listExtendedEnvironemntsNames = reExtendedEnvironments.get(extendedRuntimeEnvironment);
result = result && requiredEnvironments.stream().map(bre -> {
return bre.getProjectId();
}).allMatch(breName -> listExtendedEnvironemntsNames.contains(breName));
}
return result;
}
use of org.eclipse.n4js.runner.extension.RuntimeEnvironment in project n4js by eclipse.
the class SupportingRunnerPropertyTester method test.
/**
* Check if given receiver object is supported by given runner. Runner is specified by first arguments in args
* parameter which is expected to be runner key value.
*
* @param receiver
* is either {@link FileEditorInput} or {@link IFile} to be check against runner.
* @param property
* used to verify callers are invoking correct tester.
* @param args
* expected to contain {@link String} representing runner key of the runner to test.
* @param expectedValue
* not really used
*/
@Override
public boolean test(final Object receiver, final String property, final Object[] args, final Object expectedValue) {
if (!PROPERTY_IS_SUPPORTING_RUNNER.equals(property)) {
LOGGER.debug("invoked wrong property to test : " + property);
return false;
}
// Input is neither a file nor file editor input.
final Optional<IFile> file = getFileFromInput(receiver);
if (!file.isPresent()) {
return false;
}
// Cannot locate generated file, what to run?
if (!generatedFileLocator.tryGetGeneratedSourceForN4jsFile(file.get()).isPresent()) {
return false;
}
final Object arg0 = args[0];
if (!(arg0 instanceof String)) {
LOGGER.debug("invalid runner key value, should be String");
return false;
}
final String runnerId = arg0.toString();
final IRunnerDescriptor runnerDesc;
try {
runnerDesc = runnerRegistry.getDescriptor(runnerId);
} catch (Exception e) {
LOGGER.debug("invalid runner key value, no runner found for id: " + runnerId);
return false;
}
final List<RuntimeEnvironment> compatibleRuntimeEnvironmets = newArrayList();
try {
compatibleRuntimeEnvironmets.addAll(findCompatibleRuntimeEnvironments(file.get()));
} catch (final DependencyCycleDetectedException | InsolvableRuntimeEnvironmentException e) {
LOGGER.info(e.getMessage());
return false;
}
// TODO IDE-1351 remove the following hack once the library manager is in place
if ("org.eclipse.n4js.runner.nodejs.NODEJS".equals(runnerDesc.getId())) {
// the node-runner supports running without a custom runtime environment in the workspace
final boolean haveCustomNodeRuntimeEnvironment = hRuntimeEnvironments.findRuntimeEnvironmentProject(RuntimeEnvironment.NODEJS).isPresent();
if (!haveCustomNodeRuntimeEnvironment)
return true;
// otherwise:
// there is a custom Node.js runtime environment -> continue with the ordinary checks ...
}
// TODO IDE-1393 connect testers with extension point
if (!compatibleRuntimeEnvironmets.isEmpty() && "RE_NodeJS_Mangelhaft".equals(compatibleRuntimeEnvironmets.get(0).getProjectId())) {
return true;
}
final boolean runnerToTestIsCompatible = compatibleRuntimeEnvironmets.contains(runnerDesc.getEnvironment());
if (!runnerToTestIsCompatible) {
LOGGER.debug("Runner with id '" + runnerId + "' does not support running selected file.");
return false;
}
return true;
}
use of org.eclipse.n4js.runner.extension.RuntimeEnvironment 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);
}
Aggregations