@NotNull private VirtualFilePointerImpl getOrCreate( @NotNull Disposable parentDisposable, @Nullable VirtualFilePointerListener listener, @NotNull String path, @NotNull Pair<VirtualFile, String> fileAndUrl) { FilePointerPartNode root = myPointers.get(listener); FilePointerPartNode node; if (root == null) { root = new FilePointerPartNode(path, null, fileAndUrl); myPointers.put(listener, root); node = root; } else { node = root.findPointerOrCreate(path, 0, fileAndUrl); } VirtualFilePointerImpl pointer; if (node.leaf == null) { pointer = new VirtualFilePointerImpl(listener, parentDisposable, fileAndUrl); node.associate(pointer, fileAndUrl); } else { pointer = node.leaf; } pointer.myNode.incrementUsageCount(1); root.checkConsistency(); return pointer; }
private IdentityVirtualFilePointer getOrCreateIdentity(@NotNull String url, VirtualFile found) { IdentityVirtualFilePointer pointer = myUrlToIdentity.get(url); if (pointer == null) { pointer = new IdentityVirtualFilePointer(found, url); myUrlToIdentity.put(url, pointer); } return pointer; }
void removeNode(@NotNull FilePointerPartNode node, VirtualFilePointerListener listener) { boolean rootNodeEmpty = node.remove(); if (rootNodeEmpty) { myPointers.remove(listener); } else { myPointers.get(listener).checkConsistency(); } }
private synchronized int getNodeId(String fullTestName) { Integer nodeId = nodeIdsByFullTestName.get(fullTestName); if (nodeId == null) { nodeId = nextNodeId++; nodeIdsByFullTestName.put(fullTestName, nodeId); } return nodeId; }
public void clearState(Project project) { myGlobals = null; final String projectPath = getProjectPath(project); synchronized (myProjectDataMap) { final ProjectData data = myProjectDataMap.get(projectPath); if (data != null) { data.dropChanges(); } } }
@Override public final String getVersionString(String sdkHome) { String versionString = myCachedVersionStrings.get(sdkHome); if (versionString == null) { versionString = getJdkVersion(sdkHome); if (!StringUtil.isEmpty(versionString)) { myCachedVersionStrings.put(sdkHome, versionString); } } return versionString; }
static void registerDisposable(Disposable parentDisposable, VirtualFilePointerImpl pointer) { synchronized (ourInstances) { DelegatingDisposable result = ourInstances.get(parentDisposable); if (result == null) { ourInstances.put(parentDisposable, result = new DelegatingDisposable(parentDisposable)); Disposer.register(parentDisposable, result); } result.myCounts.put(pointer, result.myCounts.get(pointer) + 1); } }
@Override public void after(@NotNull final List<? extends VFileEvent> events) { incModificationCount(); for (FilePointerPartNode node : myPointersToUpdateUrl) { synchronized (this) { VirtualFilePointerImpl pointer = node.leaf; String urlBefore = pointer.getUrlNoUpdate(); Pair<VirtualFile, String> after = node.update(); String urlAfter = after.second; if (URL_COMPARATOR.compare(urlBefore, urlAfter) != 0) { // url has changed, reinsert FilePointerPartNode root = myPointers.get(pointer.getListener()); int useCount = node.useCount; node.remove(); FilePointerPartNode newNode = root.findPointerOrCreate(VfsUtilCore.urlToPath(urlAfter), 0, after); VirtualFilePointerImpl existingPointer = newNode.leaf; if (existingPointer != null) { // can happen when e.g. file renamed to the existing file // merge two pointers pointer.myNode = newNode; } else { newNode.associate(pointer, after); } newNode.incrementUsageCount(useCount); } } } VirtualFilePointer[] pointersToFireArray = toPointers(myPointersToFire); for (VirtualFilePointer pointer : pointersToFireArray) { ((VirtualFilePointerImpl) pointer).myNode.update(); } for (EventDescriptor event : myEvents) { event.fireAfter(); } if (pointersToFireArray.length != 0) { myBus.syncPublisher(VirtualFilePointerListener.TOPIC).validityChanged(pointersToFireArray); } myPointersToUpdateUrl = Collections.emptyList(); myEvents = Collections.emptyList(); myPointersToFire = Collections.emptyList(); for (FilePointerPartNode root : myPointers.values()) { root.checkConsistency(); } }
private void updateEditorsFromProperties() { String propertyName = getSelectedPropertyName(); ((CardLayout) myValuesPanel.getLayout()) .show(myValuesPanel, propertyName == null ? NO_PROPERTY_SELECTED : VALUES); if (propertyName == null) return; for (final PropertiesFile propertiesFile : myResourceBundle.getPropertiesFiles(myProject)) { final EditorEx editor = (EditorEx) myEditors.get(propertiesFile); if (editor == null) continue; final IProperty property = propertiesFile.findPropertyByKey(propertyName); final Document document = editor.getDocument(); CommandProcessor.getInstance() .executeCommand( null, new Runnable() { @Override public void run() { ApplicationManager.getApplication() .runWriteAction( new Runnable() { @Override public void run() { updateDocumentFromPropertyValue( getPropertyEditorValue(property), document, propertiesFile); } }); } }, "", this); JPanel titledPanel = myTitledPanels.get(propertiesFile); ((TitledBorder) titledPanel.getBorder()) .setTitleColor(property == null ? JBColor.RED : UIUtil.getLabelTextForeground()); titledPanel.repaint(); } }
@TestOnly public int countDupContainers() { Map<VirtualFilePointerContainer, Integer> c = new THashMap<VirtualFilePointerContainer, Integer>(); for (VirtualFilePointerContainerImpl container : myContainers) { Integer count = c.get(container); if (count == null) count = 0; count++; c.put(container, count); } int i = 0; for (Integer count : c.values()) { if (count > 1) { i++; } } return i; }
private void restoreCopy(VirtualFile file) { try { if (file == null) return; // Externally deleted actually. if (!file.isWritable()) return; // IDEA was unable to save it as well. So no need to restore. final byte[] bytes = mySavedCopies.get(file); if (bytes != null) { try { file.setBinaryContent(bytes, -1, mySavedTimestamps.get(file)); } catch (IOException e) { Messages.showWarningDialog( ProjectBundle.message("project.reload.write.failed", file.getPresentableUrl()), ProjectBundle.message("project.reload.write.failed.title")); } } } finally { mySavedCopies.remove(file); mySavedTimestamps.remove(file); } }
@Override public int getId( @NotNull final VirtualFile parent, @NotNull final String childName, @NotNull final NewVirtualFileSystem fs) { if (parent == mySuperRoot) { String rootUrl = normalizeRootUrl(childName, fs); VirtualFileSystemEntry root = myRoots.get(rootUrl); return root == null ? 0 : root.getId(); } int parentId = getFileId(parent); int[] children = FSRecords.list(parentId); if (children.length > 0) { // fast path, check that some child has same nameId as given name, this avoid O(N) on // retrieving names for processing non-cached children int nameId = FSRecords.getNameId(childName); for (final int childId : children) { if (nameId == FSRecords.getNameId(childId)) { return childId; } } // for case sensitive system the above check is exhaustive in consistent state of vfs } for (final int childId : children) { if (namesEqual(fs, childName, FSRecords.getName(childId))) return childId; } final VirtualFile fake = new FakeVirtualFile(parent, childName); final FileAttributes attributes = fs.getAttributes(fake); if (attributes != null) { final int child = createAndFillRecord(fs, fake, parentId, attributes); FSRecords.updateList(parentId, ArrayUtil.append(children, child)); return child; } return 0; }
@Override @Nullable public VirtualFileSystemEntry findRoot( @NotNull String basePath, @NotNull NewVirtualFileSystem fs) { if (basePath.isEmpty()) { LOG.error("Invalid root, fs=" + fs); return null; } String rootUrl = normalizeRootUrl(basePath, fs); myRootsLock.readLock().lock(); try { VirtualFileSystemEntry root = myRoots.get(rootUrl); if (root != null) return root; } finally { myRootsLock.readLock().unlock(); } final VirtualFileSystemEntry newRoot; int rootId = FSRecords.findRootRecord(rootUrl); VfsData.Segment segment = VfsData.getSegment(rootId, true); VfsData.DirectoryData directoryData = new VfsData.DirectoryData(); if (fs instanceof ArchiveFileSystem) { String parentPath = basePath.substring(0, basePath.indexOf(ArchiveFileSystem.ARCHIVE_SEPARATOR)); VirtualFile parentFile = LocalFileSystem.getInstance().findFileByPath(parentPath); if (parentFile == null) return null; FileType type = FileTypeRegistry.getInstance().getFileTypeByFileName(parentFile.getName()); if (!(type instanceof ArchiveFileType)) return null; newRoot = new ArchiveRoot(fs, rootId, segment, directoryData, parentFile); } else { newRoot = new FsRoot(fs, rootId, segment, directoryData, basePath); } FileAttributes attributes = fs.getAttributes( new StubVirtualFile() { @NotNull @Override public String getPath() { return newRoot.getPath(); } @Nullable @Override public VirtualFile getParent() { return null; } }); if (attributes == null || !attributes.isDirectory()) { return null; } boolean mark = false; myRootsLock.writeLock().lock(); try { VirtualFileSystemEntry root = myRoots.get(rootUrl); if (root != null) return root; VfsData.initFile(rootId, segment, -1, directoryData); mark = writeAttributesToRecord(rootId, 0, newRoot, fs, attributes); myRoots.put(rootUrl, newRoot); myRootsById.put(rootId, newRoot); } finally { myRootsLock.writeLock().unlock(); } if (!mark && attributes.lastModified != FSRecords.getTimestamp(rootId)) { newRoot.markDirtyRecursively(); } LOG.assertTrue( rootId == newRoot.getId(), "root=" + newRoot + " expected=" + rootId + " actual=" + newRoot.getId()); return newRoot; }
@Override @Nullable public VirtualFileSystemEntry findRoot( @NotNull String basePath, @NotNull NewVirtualFileSystem fs) { String rootUrl = normalizeRootUrl(basePath, fs); boolean isFakeRoot = basePath.isEmpty(); VirtualFileSystemEntry root; myRootsLock.readLock().lock(); try { root = isFakeRoot ? mySuperRoot : myRoots.get(rootUrl); if (root != null) return root; } finally { myRootsLock.readLock().unlock(); } myRootsLock.writeLock().lock(); try { root = isFakeRoot ? mySuperRoot : myRoots.get(rootUrl); if (root != null) return root; int rootId = FSRecords.findRootRecord(rootUrl); root = myRootsById.get(rootId); if (root != null) return root; if (isFakeRoot) { // fake super-root root = new FakeRoot(fs, rootId); } else if (fs instanceof JarFileSystem) { // optimization: for jar roots do not store base path in the myName field, use local FS // file's getPath() String parentPath = basePath.substring(0, basePath.indexOf(JarFileSystem.JAR_SEPARATOR)); VirtualFile parentLocalFile = LocalFileSystem.getInstance().findFileByPath(parentPath); if (parentLocalFile == null) return null; // check one more time since the findFileByPath could have created the root (by reentering // the findRoot) root = myRoots.get(rootUrl); if (root != null) return root; root = myRootsById.get(rootId); if (root != null) return root; root = new JarRoot(fs, rootId, parentLocalFile); } else { root = new FsRoot(fs, rootId, basePath); } if (isFakeRoot) { mySuperRoot = root; } else { FileAttributes attributes = fs.getAttributes(root); if (attributes == null || !attributes.isDirectory()) { return null; } final boolean newRoot = writeAttributesToRecord(rootId, 0, root, fs, attributes); if (!newRoot && attributes.lastModified != FSRecords.getTimestamp(rootId)) { root.markDirtyRecursively(); } myRoots.put(rootUrl, root); myRootsById.put(rootId, root); if (rootId != root.getId()) throw new AssertionError(); } return root; } finally { myRootsLock.writeLock().unlock(); } }
@Nullable public RequestFuture scheduleBuild( final Project project, final boolean isRebuild, final boolean isMake, final Collection<String> modules, final Collection<String> artifacts, final Collection<String> paths, final Map<String, String> userData, DefaultMessageHandler handler) { final String projectPath = getProjectPath(project); final UUID sessionId = UUID.randomUUID(); final CmdlineRemoteProto.Message.ControllerMessage params; CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals = myGlobals; if (globals == null) { globals = buildGlobalSettings(); myGlobals = globals; } CmdlineRemoteProto.Message.ControllerMessage.FSEvent currentFSChanges = null; final SequentialTaskExecutor projectTaskQueue; synchronized (myProjectDataMap) { ProjectData data = myProjectDataMap.get(projectPath); if (data == null) { data = new ProjectData(new SequentialTaskExecutor(myPooledThreadExecutor)); myProjectDataMap.put(projectPath, data); } if (isRebuild) { data.dropChanges(); } currentFSChanges = data.getAndResetRescanFlag() ? null : data.createNextEvent(); projectTaskQueue = data.taskQueue; } if (isRebuild) { params = CmdlineProtoUtil.createRebuildRequest(projectPath, userData, globals); } else { params = isMake ? CmdlineProtoUtil.createMakeRequest( projectPath, modules, artifacts, userData, globals, currentFSChanges) : CmdlineProtoUtil.createForceCompileRequest( projectPath, modules, artifacts, paths, userData, globals, currentFSChanges); } myMessageDispatcher.registerBuildMessageHandler(sessionId, handler, params); // ensure server is listening if (myListenPort < 0) { try { myListenPort = startListening(); } catch (Exception e) { myMessageDispatcher.unregisterBuildMessageHandler(sessionId); handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), null)); handler.sessionTerminated(); return null; } } final RequestFuture<BuilderMessageHandler> future = new RequestFuture<BuilderMessageHandler>( handler, sessionId, new RequestFuture.CancelAction<BuilderMessageHandler>() { @Override public void cancel(RequestFuture<BuilderMessageHandler> future) throws Exception { myMessageDispatcher.cancelSession(future.getRequestID()); } }); projectTaskQueue.submit( new Runnable() { @Override public void run() { try { if (project.isDisposed()) { future.cancel(false); return; } myBuildsInProgress.put(projectPath, future); final Process process = launchBuildProcess(project, myListenPort, sessionId); final OSProcessHandler processHandler = new OSProcessHandler(process, null) { @Override protected boolean shouldDestroyProcessRecursively() { return true; } }; final StringBuilder stdErrOutput = new StringBuilder(); processHandler.addProcessListener( new ProcessAdapter() { @Override public void processTerminated(ProcessEvent event) { final BuilderMessageHandler handler = myMessageDispatcher.unregisterBuildMessageHandler(sessionId); if (handler != null) { handler.sessionTerminated(); } } @Override public void onTextAvailable(ProcessEvent event, Key outputType) { // re-translate builder's output to idea.log final String text = event.getText(); if (!StringUtil.isEmpty(text)) { LOG.info("BUILDER_PROCESS [" + outputType.toString() + "]: " + text.trim()); if (stdErrOutput.length() < 1024 && ProcessOutputTypes.STDERR.equals(outputType)) { stdErrOutput.append(text); } } } }); processHandler.startNotify(); final boolean terminated = processHandler.waitFor(); if (terminated) { final int exitValue = processHandler.getProcess().exitValue(); if (exitValue != 0) { final StringBuilder msg = new StringBuilder(); msg.append("Abnormal build process termination: "); if (stdErrOutput.length() > 0) { msg.append("\n").append(stdErrOutput); } else { msg.append("unknown error"); } future .getMessageHandler() .handleFailure( sessionId, CmdlineProtoUtil.createFailure(msg.toString(), null)); } } else { future .getMessageHandler() .handleFailure( sessionId, CmdlineProtoUtil.createFailure("Disconnected from build process", null)); } } catch (ExecutionException e) { myMessageDispatcher.unregisterBuildMessageHandler(sessionId); future .getMessageHandler() .handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e)); future.getMessageHandler().sessionTerminated(); } finally { myBuildsInProgress.remove(projectPath); future.setDone(); } } }); return future; }