use of org.eclipse.n4js.xtext.workspace.WorkspaceChanges in project n4js by eclipse.
the class XWorkspaceBuilder method doIncrementalWorkspaceUpdateAndBuild.
/**
* Based on the raw, "reported changes" accumulated in {@link #newDirtyFiles} / {@link #newDeletedFiles}, do the
* following:
* <ol>
* <li>perform an update of the workspace configuration, if necessary, which may lead to additional "discovered
* changes" (e.g. resources in newly added source folders),
* <li><em>move</em> the "reported changes" together with the "discovered changes" to {@link #dirtyFiles} /
* {@link #deletedFiles} / {@link #affectedByDeletedProjects},
* <li>then trigger an incremental build.
* </ol>
*/
protected IResourceDescription.Event doIncrementalWorkspaceUpdateAndBuild(CancelIndicator cancelIndicator) {
// in case many incremental build tasks pile up in the queue (e.g. while a non-cancelable initial build is
// running), we don't want to repeatedly invoke IWorkspaceManager#update() in each of those tasks but only in
// the last one; therefore, we here check for a cancellation:
operationCanceledManager.checkCanceled(cancelIndicator);
Set<URI> newDirtyFiles = new LinkedHashSet<>(this.newDirtyFiles);
Set<URI> newDeletedFiles = new LinkedHashSet<>(this.newDeletedFiles);
boolean newRefreshRequest = this.newRefreshRequest;
this.newDirtyFiles.clear();
this.newDeletedFiles.clear();
this.newRefreshRequest = false;
Stopwatch stopwatch = Stopwatch.createStarted();
if (newRefreshRequest) {
lspLogger.log("Refreshing ...");
}
UpdateResult updateResult = workspaceManager.update(newDirtyFiles, newDeletedFiles, newRefreshRequest);
WorkspaceChanges changes = updateResult.changes;
List<URI> actualDirtyFiles = UtilN4.concat(changes.getAddedURIs(), changes.getChangedURIs());
List<URI> actualDeletedFiles = new ArrayList<>(changes.getRemovedURIs());
if (newRefreshRequest) {
// scan all source folders of all projects for source file additions, changes, and deletions
// - including source files of added projects,
// - including source files of added source folders of existing projects,
// - including source files of removed source folders of existing projects,
// - *not* including source files of removed projects.
actualDirtyFiles = new ArrayList<>();
actualDeletedFiles = new ArrayList<>();
for (ProjectBuilder projectBuilder : workspaceManager.getProjectBuilders()) {
ResourceChangeSet sourceFileChanges = projectBuilder.scanForSourceFileChanges();
actualDirtyFiles.addAll(sourceFileChanges.getDirty());
actualDeletedFiles.addAll(sourceFileChanges.getDeleted());
}
} else {
// scan only the added source folders (including those of added projects) for source files
actualDirtyFiles.addAll(scanAddedSourceFoldersForNewSourceFiles(changes, scanner));
// collect URIs from removed source folders (*not* including those of removed projects)
actualDeletedFiles.addAll(getURIsFromRemovedSourceFolders(changes));
}
queue(this.dirtyFiles, actualDeletedFiles, actualDirtyFiles);
queue(this.deletedFiles, actualDirtyFiles, actualDeletedFiles);
// take care of removed projects
Set<ProjectConfigSnapshot> deletedProjects = new HashSet<>();
for (ProjectConfigSnapshot prjConfig : changes.getRemovedProjects()) {
deletedProjects.add(prjConfig);
}
for (ProjectConfigSnapshot prjConfig : Iterables.concat(changes.getAddedProjects(), changes.getChangedProjects())) {
deletedProjects.remove(prjConfig);
}
for (ProjectConfigSnapshot delPrj : deletedProjects) {
ImmutableSet<? extends ProjectConfigSnapshot> affected = updateResult.oldWorkspaceConfigSnapshot.getProjectsDependingOn(delPrj.getName());
this.affectedByDeletedProjects.addAll(affected);
}
handleContentsOfRemovedProjects(updateResult.removedProjectsContents);
if (newRefreshRequest) {
lspLogger.log("... refresh done (" + stopwatch.toString() + "; " + "projects added/removed: " + changes.getAddedProjects().size() + "/" + changes.getRemovedProjects().size() + "; " + "files dirty/deleted: " + dirtyFiles.size() + "/" + deletedFiles.size() + ").");
}
for (String cyclicProject : updateResult.cyclicProjectChanges) {
ProjectConfigSnapshot projectConfig = workspaceManager.getWorkspaceConfig().findProjectByID(cyclicProject);
Collection<URI> projectDescriptionUris = projectConfig.getProjectDescriptionUris();
dirtyFiles.addAll(projectDescriptionUris);
}
if (dirtyFiles.isEmpty() && deletedFiles.isEmpty() && affectedByDeletedProjects.isEmpty()) {
return new ResourceDescriptionChangeEvent(Collections.emptyList());
}
return doIncrementalBuild(cancelIndicator);
}
use of org.eclipse.n4js.xtext.workspace.WorkspaceChanges in project n4js by eclipse.
the class N4JSProjectConfig method computeChanges.
/**
* Given two project configuration snapshots representing the old and new state of the receiving project, this
* method computes the corresponding workspace changes. If no changes occurred, an empty {@link WorkspaceChanges}
* instance will be returned.
*/
public static WorkspaceChanges computeChanges(ProjectConfigSnapshot oldProjectConfig, ProjectConfigSnapshot newProjectConfig) {
Set<? extends SourceFolderSnapshot> oldSourceFolders = oldProjectConfig.getSourceFolders();
Set<? extends SourceFolderSnapshot> newSourceFolders = newProjectConfig.getSourceFolders();
// detect added/removed source folders
Map<URI, SourceFolderSnapshot> oldSFs = new HashMap<>();
Map<URI, SourceFolderSnapshot> newSFs = new HashMap<>();
for (SourceFolderSnapshot sourceFolder : oldSourceFolders) {
oldSFs.put(sourceFolder.getPath(), sourceFolder);
}
for (SourceFolderSnapshot sourceFolder : newSourceFolders) {
newSFs.put(sourceFolder.getPath(), sourceFolder);
}
List<SourceFolderSnapshot> addedSourceFolders = new ArrayList<>();
List<SourceFolderSnapshot> removedSourceFolders = new ArrayList<>();
for (URI sfUri : Iterables.concat(oldSFs.keySet(), newSFs.keySet())) {
boolean isOld = oldSFs.containsKey(sfUri);
boolean isNew = newSFs.containsKey(sfUri);
if (isOld && isNew) {
// unchanged
} else if (isOld && !isNew) {
removedSourceFolders.add(oldSFs.get(sfUri));
} else if (!isOld && isNew) {
addedSourceFolders.add(newSFs.get(sfUri));
}
}
if (Objects.equals(oldProjectConfig.getName(), newProjectConfig.getName())) {
// detect changes in project properties
boolean propertiesChanged = !addedSourceFolders.isEmpty() || !removedSourceFolders.isEmpty() || !Objects.equals(oldProjectConfig, newProjectConfig);
return new WorkspaceChanges(ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), ImmutableList.copyOf(removedSourceFolders), ImmutableList.copyOf(addedSourceFolders), ImmutableList.of(), ImmutableList.of(), propertiesChanged ? ImmutableList.of(newProjectConfig) : ImmutableList.of());
} else {
return new WorkspaceChanges(ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), ImmutableList.copyOf(removedSourceFolders), ImmutableList.copyOf(addedSourceFolders), ImmutableList.of(oldProjectConfig), ImmutableList.of(newProjectConfig), ImmutableList.of());
}
}
use of org.eclipse.n4js.xtext.workspace.WorkspaceChanges in project n4js by eclipse.
the class N4JSWorkspaceConfig method update.
@Override
public WorkspaceChanges update(WorkspaceConfigSnapshot oldWorkspaceConfig, Set<URI> dirtyFiles, Set<URI> deletedFiles, boolean refresh) {
WorkspaceChanges changes = refresh ? doCompleteUpdate(oldWorkspaceConfig) : doMinimalUpdate(oldWorkspaceConfig, dirtyFiles, deletedFiles);
changes = recomputeSemanticDependenciesIfNecessary(oldWorkspaceConfig, changes);
return changes;
}
use of org.eclipse.n4js.xtext.workspace.WorkspaceChanges in project n4js by eclipse.
the class N4JSWorkspaceConfig method detectAddedRemovedProjects.
private WorkspaceChanges detectAddedRemovedProjects(WorkspaceConfigSnapshot oldWorkspaceConfig, boolean alsoDetectChangedProjects) {
// update all projects
reloadAllProjectInformationFromDisk();
// detect project additions, removals (and also changes, iff 'alsoDetectChangedProjects' is set)
Map<URI, ProjectConfigSnapshot> oldProjectsMap = IterableExtensions.toMap(oldWorkspaceConfig.getProjects(), ProjectConfigSnapshot::getPath);
Map<URI, N4JSProjectConfig> newProjectsMap = IterableExtensions.toMap(getProjects(), XIProjectConfig::getPath);
WorkspaceChanges changes = new WorkspaceChanges();
for (URI uri : Sets.union(oldProjectsMap.keySet(), newProjectsMap.keySet())) {
boolean isOld = oldProjectsMap.containsKey(uri);
boolean isNew = newProjectsMap.containsKey(uri);
if (isOld && !isNew) {
// deleted
changes = changes.merge(WorkspaceChanges.createProjectRemoved(oldProjectsMap.get(uri)));
} else if (!isOld && isNew) {
// added
ProjectConfigSnapshot newPC = configSnapshotFactory.createProjectConfigSnapshot(newProjectsMap.get(uri));
changes = changes.merge(WorkspaceChanges.createProjectAdded(newPC));
} else if (isOld && isNew) {
// check name change
String oldPackageName = ((N4JSProjectConfigSnapshot) oldProjectsMap.get(uri)).getPackageName();
String newPackageName = newProjectsMap.get(uri).getPackageName();
if (Objects.equals(oldPackageName, newPackageName)) {
// no change
if (alsoDetectChangedProjects) {
ProjectConfigSnapshot oldPC = oldProjectsMap.get(uri);
ProjectConfigSnapshot newPC = configSnapshotFactory.createProjectConfigSnapshot(newProjectsMap.get(uri));
changes = changes.merge(N4JSProjectConfig.computeChanges(oldPC, newPC));
}
} else {
// names changed
ProjectConfigSnapshot newPC = configSnapshotFactory.createProjectConfigSnapshot(newProjectsMap.get(uri));
changes = changes.merge(WorkspaceChanges.createProjectAdded(newPC));
changes = changes.merge(WorkspaceChanges.createProjectRemoved(oldProjectsMap.get(uri)));
}
}
}
return changes;
}
use of org.eclipse.n4js.xtext.workspace.WorkspaceChanges in project n4js by eclipse.
the class N4JSWorkspaceConfig method doMinimalUpdate.
/**
* Based on the given dirty/deleted files, performs a workspace update with as few computations as possible.
*/
private WorkspaceChanges doMinimalUpdate(WorkspaceConfigSnapshot oldWorkspaceConfig, Set<URI> dirtyFiles, Set<URI> deletedFiles) {
WorkspaceChanges changes = WorkspaceChanges.createUrisRemovedAndChanged(deletedFiles, dirtyFiles);
boolean needToDetectAddedRemovedProjects = false;
for (URI changedResource : Iterables.concat(dirtyFiles, deletedFiles)) {
String lastSegment = changedResource.lastSegment();
boolean isPackageJson = lastSegment != null && lastSegment.equals(N4JSGlobals.PACKAGE_JSON);
if (!isPackageJson) {
continue;
}
ProjectConfigSnapshot oldProject = oldWorkspaceConfig.findProjectContaining(changedResource);
XIProjectConfig project = oldProject != null ? findProjectByName(oldProject.getName()) : null;
if (oldProject != null && project != null) {
// an existing project was modified (maybe removed)
changes = changes.merge(((N4JSProjectConfig) project).update(oldWorkspaceConfig, changedResource, configSnapshotFactory));
if (((N4JSProjectConfig) project).isWorkspaceProject()) {
needToDetectAddedRemovedProjects = true;
}
} else {
// a new project was created
needToDetectAddedRemovedProjects = true;
}
}
needToDetectAddedRemovedProjects |= isProjectDiscoveryRequired(changes, oldWorkspaceConfig);
if (needToDetectAddedRemovedProjects) {
changes = changes.merge(detectAddedRemovedProjects(oldWorkspaceConfig, false));
}
return changes;
}
Aggregations