Search in sources :

Example 1 with ResourceChangeSet

use of org.eclipse.n4js.xtext.ide.server.ResourceChangeSet 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);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Stopwatch(com.google.common.base.Stopwatch) ArrayList(java.util.ArrayList) ResourceChangeSet(org.eclipse.n4js.xtext.ide.server.ResourceChangeSet) URI(org.eclipse.emf.common.util.URI) ResourceDescriptionChangeEvent(org.eclipse.xtext.resource.impl.ResourceDescriptionChangeEvent) WorkspaceChanges(org.eclipse.n4js.xtext.workspace.WorkspaceChanges) ProjectConfigSnapshot(org.eclipse.n4js.xtext.workspace.ProjectConfigSnapshot) UpdateResult(org.eclipse.n4js.xtext.ide.server.build.XWorkspaceManager.UpdateResult) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 2 with ResourceChangeSet

use of org.eclipse.n4js.xtext.ide.server.ResourceChangeSet in project n4js by eclipse.

the class ProjectBuilder method readProjectState.

/**
 * Reads the persisted project state from disk
 *
 * @return set of all source URIs with modified contents
 */
private ResourceChangeSet readProjectState() {
    if (persisterConfig.isDeleteState(projectConfig)) {
        deletePersistenceFile();
    }
    ResourceChangeSet result = new ResourceChangeSet();
    // sets this#projectStateSnapshot to an empty project state
    doClearWithoutNotification();
    boolean fullBuildRequired = false;
    ImmutableProjectState projectState = projectStatePersister.readProjectState(projectConfig);
    if (projectState != null) {
        fullBuildRequired |= handleProjectAdditionRemovalSinceProjectStateWasComputed(result, projectState);
        setProjectIndex(projectState.internalGetResourceDescriptions());
        this.projectStateSnapshot.set(projectState);
    }
    if (fullBuildRequired) {
        result.getDirty().addAll(scanForSourceFiles());
    } else {
        result.addAll(scanForSourceFileChanges());
    }
    return result;
}
Also used : ResourceChangeSet(org.eclipse.n4js.xtext.ide.server.ResourceChangeSet)

Example 3 with ResourceChangeSet

use of org.eclipse.n4js.xtext.ide.server.ResourceChangeSet in project n4js by eclipse.

the class ProjectBuilder method scanForSourceFileChanges.

/**
 * Scans the files system and returns URIs of source files that were added, changed, removed since this builder's
 * current {@link #projectStateSnapshot project state} was created. Content changes in source files are detected by
 * way of hash comparison.
 */
public ResourceChangeSet scanForSourceFileChanges() {
    ResourceChangeSet result = new ResourceChangeSet();
    ImmutableProjectState oldProjectState = this.projectStateSnapshot.get();
    Map<URI, HashedFileContent> oldHashes = oldProjectState.getFileHashes();
    Set<URI> oldSourceFilesURIs = oldProjectState.internalGetResourceDescriptions().getAllURIs();
    Set<URI> existingSourceFileURIs = scanForSourceFiles();
    for (URI currURI : Sets.union(oldSourceFilesURIs, existingSourceFileURIs)) {
        boolean isOld = oldSourceFilesURIs.contains(currURI);
        boolean isNew = existingSourceFileURIs.contains(currURI);
        if (!isOld && isNew) {
            // added
            result.getDirty().add(currURI);
        } else if (isOld && !isNew) {
            // removed
            result.getDeleted().add(currURI);
        } else if (isOld && isNew) {
            // compare hash ...
            HashedFileContent hfc = oldHashes.get(currURI);
            if (hfc != null) {
                switch(getSourceChangeKind(hfc, oldProjectState)) {
                    case UNCHANGED:
                        {
                            break;
                        }
                    case CHANGED:
                        {
                            result.getDirty().add(currURI);
                            break;
                        }
                    case DELETED:
                        {
                            result.getDeleted().add(currURI);
                            break;
                        }
                }
            } else {
                LOG.warn("inconsistency in project state: URI is indexed but not hashed: " + currURI);
                result.getDirty().add(currURI);
            }
        }
    }
    return result;
}
Also used : ResourceChangeSet(org.eclipse.n4js.xtext.ide.server.ResourceChangeSet) URI(org.eclipse.emf.common.util.URI)

Example 4 with ResourceChangeSet

use of org.eclipse.n4js.xtext.ide.server.ResourceChangeSet in project n4js by eclipse.

the class ProjectBuilder method handleProjectAdditionRemovalSinceProjectStateWasComputed.

/**
 * @return <code>true</code> iff full build of this builder's project is required due to project changes.
 */
protected boolean handleProjectAdditionRemovalSinceProjectStateWasComputed(ResourceChangeSet result, ImmutableProjectState projectState) {
    Set<String> oldExistingDeps = FluentIterable.from(projectState.getDependencies().entrySet()).filter(// value tells whether project did exist when project state was computed
    Entry::getValue).transform(Entry::getKey).toSet();
    Set<String> newExistingDeps = FluentIterable.from(projectConfig.getDependencies()).filter(depName -> workspaceIndex.getProjectConfig(depName) != null).toSet();
    if (!Sets.difference(oldExistingDeps, newExistingDeps).isEmpty()) {
        // -> therefore we simply perform a full build of this builder's project
        return true;
    }
    for (String depName : Sets.difference(newExistingDeps, oldExistingDeps)) {
        // project 'depName' was added since 'projectState' was persisted
        // -> treat all resources that exist now in that added project as newly created, by creating additional
        // external deltas for them
        ResourceDescriptionsData addedDepIndex = workspaceIndex.getProjectIndex(depName);
        if (addedDepIndex != null) {
            FluentIterable.from(addedDepIndex.getAllResourceDescriptions()).transform(desc -> new DefaultResourceDescriptionDelta(null, desc)).copyInto(result.getAdditionalExternalDeltas());
        }
    }
    return false;
}
Also used : Notification(org.eclipse.emf.common.notify.Notification) Inject(com.google.inject.Inject) UtilN4(org.eclipse.n4js.utils.UtilN4) IResourceDescription(org.eclipse.xtext.resource.IResourceDescription) URIUtils(org.eclipse.n4js.utils.URIUtils) IFileSystemScanner(org.eclipse.xtext.util.IFileSystemScanner) Logger(org.apache.log4j.Logger) IExternalContentSupport(org.eclipse.xtext.resource.IExternalContentSupport) OutputConfiguration(org.eclipse.xtext.generator.OutputConfiguration) FluentIterable(com.google.common.collect.FluentIterable) Map(java.util.Map) XIProjectDescriptionFactory(org.eclipse.n4js.xtext.ide.server.XIProjectDescriptionFactory) ResourceChangeSet(org.eclipse.n4js.xtext.ide.server.ResourceChangeSet) Delta(org.eclipse.xtext.resource.IResourceDescription.Delta) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableMap(com.google.common.collect.ImmutableMap) OperationCanceledManager(org.eclipse.xtext.service.OperationCanceledManager) Set(java.util.Set) ProjectConfigSnapshot(org.eclipse.n4js.xtext.workspace.ProjectConfigSnapshot) ResourceDescriptionsData(org.eclipse.xtext.resource.impl.ResourceDescriptionsData) AfterDeleteListener(org.eclipse.n4js.xtext.ide.server.build.XBuildRequest.AfterDeleteListener) AfterValidateListener(org.eclipse.n4js.xtext.ide.server.build.XBuildRequest.AfterValidateListener) Sets(com.google.common.collect.Sets) PublishingIssueAcceptor(org.eclipse.n4js.xtext.ide.server.issues.PublishingIssueAcceptor) List(java.util.List) IssueImpl(org.eclipse.xtext.validation.Issue.IssueImpl) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) Entry(java.util.Map.Entry) Resource(org.eclipse.emf.ecore.resource.Resource) AfterBuildRequestListener(org.eclipse.n4js.xtext.ide.server.build.XBuildRequest.AfterBuildRequestListener) ChunkedResourceDescriptions(org.eclipse.xtext.resource.impl.ChunkedResourceDescriptions) ProjectDescription(org.eclipse.xtext.resource.impl.ProjectDescription) URI(org.eclipse.emf.common.util.URI) IResourceServiceProvider(org.eclipse.xtext.resource.IResourceServiceProvider) HashMap(java.util.HashMap) OutputConfigurationProvider(org.eclipse.xtext.generator.OutputConfigurationProvider) AtomicReference(java.util.concurrent.atomic.AtomicReference) ResourceSet(org.eclipse.emf.ecore.resource.ResourceSet) ArrayList(java.util.ArrayList) UriUtil(org.eclipse.xtext.util.UriUtil) HashSet(java.util.HashSet) SourceFolderScanner(org.eclipse.n4js.xtext.workspace.SourceFolderScanner) ImmutableList(com.google.common.collect.ImmutableList) CancelIndicator(org.eclipse.xtext.util.CancelIndicator) Severity(org.eclipse.xtext.diagnostics.Severity) IOException(java.io.IOException) File(java.io.File) WorkspaceConfigSnapshot(org.eclipse.n4js.xtext.workspace.WorkspaceConfigSnapshot) SourceFolderSnapshot(org.eclipse.n4js.xtext.workspace.SourceFolderSnapshot) Provider(com.google.inject.Provider) Issue(org.eclipse.xtext.validation.Issue) AdapterImpl(org.eclipse.emf.common.notify.impl.AdapterImpl) LogManager(org.apache.log4j.LogManager) ProjectStatePersisterConfig(org.eclipse.n4js.xtext.ide.server.ProjectStatePersisterConfig) Collections(java.util.Collections) DefaultResourceDescriptionDelta(org.eclipse.xtext.resource.impl.DefaultResourceDescriptionDelta) ResourceDescriptionsData(org.eclipse.xtext.resource.impl.ResourceDescriptionsData) Entry(java.util.Map.Entry) DefaultResourceDescriptionDelta(org.eclipse.xtext.resource.impl.DefaultResourceDescriptionDelta)

Example 5 with ResourceChangeSet

use of org.eclipse.n4js.xtext.ide.server.ResourceChangeSet in project n4js by eclipse.

the class ProjectBuilder method doInitialBuild.

/**
 * Initial build reads the project state and resolves changes. Generate output files.
 * <p>
 * This method assumes that it is only invoked in situations when the client does not have any diagnostics stored,
 * e.g. directly after invoking {@link #doClean(XBuildRequest, CancelIndicator)}. Therefore no 'publishDiagnostics'
 * events with an empty list of diagnostics need to be sent to the client in order to remove obsolete diagnostics.
 * <p>
 * NOTE: this is not only invoked shortly after server startup but also at various other occasions, for example
 * <ul>
 * <li>when the client executes the {@code N4JSCommandService#rebuild(ILanguageServerAccess, CancelIndicator)
 * rebuild command},
 * <li>when the workspace folder is changed in VS Code.
 * </ul>
 */
public XBuildResult doInitialBuild(IBuildRequestFactory buildRequestFactory, List<Delta> externalDeltas) {
    ResourceChangeSet changeSet = readProjectState();
    XBuildResult result = doBuild(createInitialBuildRequestFactory(buildRequestFactory), changeSet.getDirty(), changeSet.getDeleted(), UtilN4.concat(externalDeltas, changeSet.getAdditionalExternalDeltas()), CancelIndicator.NullImpl);
    // clear the resource set to release memory
    clearResourceSet();
    LOG.info("Project built: " + this.projectConfig.getName());
    return result;
}
Also used : ResourceChangeSet(org.eclipse.n4js.xtext.ide.server.ResourceChangeSet)

Aggregations

ResourceChangeSet (org.eclipse.n4js.xtext.ide.server.ResourceChangeSet)5 URI (org.eclipse.emf.common.util.URI)3 ArrayList (java.util.ArrayList)2 HashSet (java.util.HashSet)2 ProjectConfigSnapshot (org.eclipse.n4js.xtext.workspace.ProjectConfigSnapshot)2 Stopwatch (com.google.common.base.Stopwatch)1 FluentIterable (com.google.common.collect.FluentIterable)1 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableListMultimap (com.google.common.collect.ImmutableListMultimap)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 ImmutableSet (com.google.common.collect.ImmutableSet)1 Sets (com.google.common.collect.Sets)1 Inject (com.google.inject.Inject)1 Provider (com.google.inject.Provider)1 File (java.io.File)1 IOException (java.io.IOException)1 Collections (java.util.Collections)1 HashMap (java.util.HashMap)1 LinkedHashSet (java.util.LinkedHashSet)1 List (java.util.List)1