@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;
  }
  @Override
  public void saveAllDocuments() {
    ApplicationManager.getApplication().assertIsDispatchThread();

    myMultiCaster.beforeAllDocumentsSaving();
    if (myUnsavedDocuments.isEmpty()) return;

    final Map<Document, IOException> failedToSave = new HashMap<Document, IOException>();
    final Set<Document> vetoed = new HashSet<Document>();
    while (true) {
      int count = 0;

      for (Document document : myUnsavedDocuments) {
        if (failedToSave.containsKey(document)) continue;
        if (vetoed.contains(document)) continue;
        try {
          doSaveDocument(document);
        } catch (IOException e) {
          //noinspection ThrowableResultOfMethodCallIgnored
          failedToSave.put(document, e);
        } catch (SaveVetoException e) {
          vetoed.add(document);
        }
        count++;
      }

      if (count == 0) break;
    }

    if (!failedToSave.isEmpty()) {
      handleErrorsOnSave(failedToSave);
    }
  }
  @NotNull
  private static Map<Module, String> collectJpsPluginModules(@NotNull Module module) {
    XmlFile pluginXml = PluginModuleType.getPluginXml(module);
    if (pluginXml == null) return Collections.emptyMap();

    DomFileElement<IdeaPlugin> fileElement =
        DomManager.getDomManager(module.getProject()).getFileElement(pluginXml, IdeaPlugin.class);
    if (fileElement == null) return Collections.emptyMap();

    Map<Module, String> jpsPluginToOutputPath = new HashMap<Module, String>();
    IdeaPlugin plugin = fileElement.getRootElement();
    List<Extensions> extensions = plugin.getExtensions();
    for (Extensions extensionGroup : extensions) {
      XmlTag extensionsTag = extensionGroup.getXmlTag();
      String defaultExtensionNs = extensionsTag.getAttributeValue("defaultExtensionNs");
      for (XmlTag tag : extensionsTag.getSubTags()) {
        String name = tag.getLocalName();
        String qualifiedName = defaultExtensionNs != null ? defaultExtensionNs + "." + name : name;
        if (CompileServerPlugin.EP_NAME.getName().equals(qualifiedName)) {
          String classpath = tag.getAttributeValue("classpath");
          if (classpath != null) {
            for (String path : StringUtil.split(classpath, ";")) {
              String moduleName = FileUtil.getNameWithoutExtension(PathUtil.getFileName(path));
              Module jpsModule =
                  ModuleManager.getInstance(module.getProject()).findModuleByName(moduleName);
              if (jpsModule != null) {
                jpsPluginToOutputPath.put(jpsModule, path);
              }
            }
          }
        }
      }
    }
    return jpsPluginToOutputPath;
  }
示例#4
0
  public void collectCommonPluginRoots(
      Map<String, VirtualFile> result, @NotNull Module module, boolean refresh) {
    if (isCommonPluginsModule(module)) {
      for (VirtualFile root : ModuleRootManager.getInstance(module).getContentRoots()) {
        String pluginName = getInstalledPluginNameByPath(module.getProject(), root);
        if (pluginName != null) {
          result.put(pluginName, root);
        }
      }
    } else {
      VirtualFile root = findAppRoot(module);
      if (root == null) return;

      extractPlugins(
          module.getProject(), root.findChild(MvcModuleStructureUtil.PLUGINS_DIRECTORY), result);
      extractPlugins(
          module.getProject(),
          MvcModuleStructureUtil.findFile(getCommonPluginsDir(module), refresh),
          result);
      extractPlugins(
          module.getProject(),
          MvcModuleStructureUtil.findFile(getGlobalPluginsDir(module), refresh),
          result);
    }
  }
 private synchronized int getNodeId(String fullTestName) {
   Integer nodeId = nodeIdsByFullTestName.get(fullTestName);
   if (nodeId == null) {
     nodeId = nextNodeId++;
     nodeIdsByFullTestName.put(fullTestName, nodeId);
   }
   return nodeId;
 }
 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;
 }
 private void copyToTemp(VirtualFile file) {
   try {
     final byte[] bytes = file.contentsToByteArray();
     mySavedCopies.put(file, bytes);
     mySavedTimestamps.put(file, file.getTimeStamp());
   } catch (IOException e) {
     LOG.error(e);
   }
 }
 @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);
      }
    }
示例#10
0
 private void extractPlugins(
     Project project, @Nullable VirtualFile pluginRoot, Map<String, VirtualFile> res) {
   if (pluginRoot != null) {
     VirtualFile[] children = pluginRoot.getChildren();
     if (children != null) {
       for (VirtualFile child : children) {
         String pluginName = getInstalledPluginNameByPath(project, child);
         if (pluginName != null) {
           res.put(pluginName, child);
         }
       }
     }
   }
 }
示例#11
0
  public static void addJavaHome(@NotNull JavaParameters params, @NotNull Module module) {
    final Sdk sdk = ModuleUtilCore.getSdk(module, JavaModuleExtensionImpl.class);
    if (sdk != null && sdk.getSdkType() instanceof JavaSdkType) {
      String path = StringUtil.trimEnd(sdk.getHomePath(), File.separator);
      if (StringUtil.isNotEmpty(path)) {
        Map<String, String> env = params.getEnv();
        if (env == null) {
          env = new HashMap<String, String>();
          params.setEnv(env);
        }

        env.put("JAVA_HOME", FileUtil.toSystemDependentName(path));
      }
    }
  }
 @Override
 public void projectOpened(final Project project) {
   final MessageBusConnection conn = project.getMessageBus().connect();
   myConnections.put(project, conn);
   conn.subscribe(
       ProjectTopics.PROJECT_ROOTS,
       new ModuleRootAdapter() {
         @Override
         public void rootsChanged(final ModuleRootEvent event) {
           final Object source = event.getSource();
           if (source instanceof Project) {
             clearState((Project) source);
           }
         }
       });
 }
 private void runAutoMake() {
   if (ApplicationManager.getApplication().isUnitTestMode()) {
     return;
   }
   final Project[] openProjects = myProjectManager.getOpenProjects();
   if (openProjects.length > 0) {
     final List<RequestFuture> futures = new ArrayList<RequestFuture>();
     for (final Project project : openProjects) {
       if (project.isDefault() || project.isDisposed()) {
         continue;
       }
       final CompilerWorkspaceConfiguration config =
           CompilerWorkspaceConfiguration.getInstance(project);
       if (!config.useOutOfProcessBuild() || !config.MAKE_PROJECT_ON_SAVE) {
         continue;
       }
       final List<String> emptyList = Collections.emptyList();
       final RequestFuture future =
           scheduleBuild(
               project,
               false,
               true,
               emptyList,
               emptyList,
               emptyList,
               Collections.<String, String>emptyMap(),
               new AutoMakeMessageHandler(project));
       if (future != null) {
         futures.add(future);
         synchronized (myAutomakeFutures) {
           myAutomakeFutures.put(future, project);
         }
       }
     }
     try {
       for (RequestFuture future : futures) {
         future.waitFor();
       }
     } finally {
       synchronized (myAutomakeFutures) {
         myAutomakeFutures.keySet().removeAll(futures);
       }
     }
   }
 }
 @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;
 }
  @Override
  @Nullable
  public Project newProject(
      final String projectName,
      @NotNull String filePath,
      boolean useDefaultProjectSettings,
      boolean isDummy) {
    filePath = toCanonicalName(filePath);

    //noinspection ConstantConditions
    if (LOG_PROJECT_LEAKAGE_IN_TESTS && ApplicationManager.getApplication().isUnitTestMode()) {
      for (int i = 0; i < 42; i++) {
        if (myProjects.size() < MAX_LEAKY_PROJECTS) break;
        System.gc();
        TimeoutUtil.sleep(100);
        System.gc();
      }

      if (myProjects.size() >= MAX_LEAKY_PROJECTS) {
        List<Project> copy = new ArrayList<Project>(myProjects.keySet());
        myProjects.clear();
        throw new TooManyProjectLeakedException(copy);
      }
    }

    ProjectImpl project =
        createProject(
            projectName, filePath, false, ApplicationManager.getApplication().isUnitTestMode());
    try {
      initProject(project, useDefaultProjectSettings ? (ProjectImpl) getDefaultProject() : null);
      if (LOG_PROJECT_LEAKAGE_IN_TESTS) {
        myProjects.put(project, null);
      }
      return project;
    } catch (final Exception e) {
      LOG.info(e);
      Messages.showErrorDialog(message(e), ProjectBundle.message("project.load.default.error"));
    }
    return null;
  }
  @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;
  }
  private void recreateEditorsPanel() {
    myValuesPanel.removeAll();
    myValuesPanel.setLayout(new CardLayout());

    if (!myProject.isOpen()) return;
    JPanel valuesPanelComponent = new MyJPanel(new GridBagLayout());
    myValuesPanel.add(
        new JBScrollPane(valuesPanelComponent) {
          @Override
          public void updateUI() {
            super.updateUI();
            getViewport().setBackground(UIUtil.getPanelBackground());
          }
        },
        VALUES);
    myValuesPanel.add(myNoPropertySelectedPanel, NO_PROPERTY_SELECTED);

    List<PropertiesFile> propertiesFiles = myResourceBundle.getPropertiesFiles();

    GridBagConstraints gc =
        new GridBagConstraints(
            0,
            0,
            0,
            0,
            0,
            0,
            GridBagConstraints.NORTHWEST,
            GridBagConstraints.BOTH,
            new Insets(5, 5, 5, 5),
            0,
            0);
    releaseAllEditors();
    myTitledPanels.clear();
    int y = 0;
    Editor previousEditor = null;
    Editor firstEditor = null;
    for (final PropertiesFile propertiesFile : propertiesFiles) {
      final Editor editor = createEditor();
      final Editor oldEditor = myEditors.put(propertiesFile, editor);
      if (firstEditor == null) {
        firstEditor = editor;
      }
      if (previousEditor != null) {
        editor.putUserData(
            ChooseSubsequentPropertyValueEditorAction.PREV_EDITOR_KEY, previousEditor);
        previousEditor.putUserData(
            ChooseSubsequentPropertyValueEditorAction.NEXT_EDITOR_KEY, editor);
      }
      previousEditor = editor;
      if (oldEditor != null) {
        EditorFactory.getInstance().releaseEditor(oldEditor);
      }
      ((EditorEx) editor)
          .addFocusListener(
              new FocusChangeListener() {
                @Override
                public void focusGained(final Editor editor) {
                  mySelectedEditor = editor;
                }

                @Override
                public void focusLost(final Editor eventEditor) {
                  writeEditorPropertyValue(editor, propertiesFile, null);
                }
              });
      gc.gridx = 0;
      gc.gridy = y++;
      gc.gridheight = 1;
      gc.gridwidth = GridBagConstraints.REMAINDER;
      gc.weightx = 1;
      gc.weighty = 1;
      gc.anchor = GridBagConstraints.CENTER;

      Locale locale = propertiesFile.getLocale();
      List<String> names = new ArrayList<String>();
      if (!Comparing.strEqual(locale.getDisplayLanguage(), null)) {
        names.add(locale.getDisplayLanguage());
      }
      if (!Comparing.strEqual(locale.getDisplayCountry(), null)) {
        names.add(locale.getDisplayCountry());
      }
      if (!Comparing.strEqual(locale.getDisplayVariant(), null)) {
        names.add(locale.getDisplayVariant());
      }

      String title = propertiesFile.getName();
      if (!names.isEmpty()) {
        title += " (" + StringUtil.join(names, "/") + ")";
      }
      JComponent comp =
          new JPanel(new BorderLayout()) {
            @Override
            public Dimension getPreferredSize() {
              Insets insets = getBorder().getBorderInsets(this);
              return new Dimension(100, editor.getLineHeight() * 4 + insets.top + insets.bottom);
            }
          };
      comp.add(editor.getComponent(), BorderLayout.CENTER);
      comp.setBorder(IdeBorderFactory.createTitledBorder(title, true));
      myTitledPanels.put(propertiesFile, (JPanel) comp);

      valuesPanelComponent.add(comp, gc);
    }
    if (previousEditor != null) {
      previousEditor.putUserData(
          ChooseSubsequentPropertyValueEditorAction.NEXT_EDITOR_KEY, firstEditor);
      firstEditor.putUserData(
          ChooseSubsequentPropertyValueEditorAction.PREV_EDITOR_KEY, previousEditor);
    }

    gc.gridx = 0;
    gc.gridy = y;
    gc.gridheight = GridBagConstraints.REMAINDER;
    gc.gridwidth = GridBagConstraints.REMAINDER;
    gc.weightx = 10;
    gc.weighty = 1;

    valuesPanelComponent.add(new JPanel(), gc);
    selectionChanged();
    myValuesPanel.repaint();
    UIUtil.invokeAndWaitIfNeeded(
        new Runnable() {
          @Override
          public void run() {
            updateEditorsFromProperties();
          }
        });
  }
  @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();
    }
  }
示例#19
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;
  }
  private static CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings buildGlobalSettings() {
    final Map<String, String> data = new HashMap<String, String>();

    for (Map.Entry<String, String> entry : PathMacrosImpl.getGlobalSystemMacros().entrySet()) {
      data.put(entry.getKey(), FileUtil.toSystemIndependentName(entry.getValue()));
    }

    final PathMacros pathVars = PathMacros.getInstance();
    for (String name : pathVars.getAllMacroNames()) {
      final String path = pathVars.getValue(name);
      if (path != null) {
        data.put(name, FileUtil.toSystemIndependentName(path));
      }
    }

    final List<GlobalLibrary> globals = new ArrayList<GlobalLibrary>();

    fillSdks(globals);
    fillGlobalLibraries(globals);

    final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.Builder cmdBuilder =
        CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.newBuilder();

    if (!data.isEmpty()) {
      for (Map.Entry<String, String> entry : data.entrySet()) {
        final String var = entry.getKey();
        final String value = entry.getValue();
        if (var != null && value != null) {
          cmdBuilder.addPathVariable(CmdlineProtoUtil.createPair(var, value));
        }
      }
    }

    if (!globals.isEmpty()) {
      for (GlobalLibrary lib : globals) {
        final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.GlobalLibrary.Builder
            libBuilder =
                CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.GlobalLibrary
                    .newBuilder();
        libBuilder.setName(lib.getName()).addAllPath(lib.getPaths());
        if (lib instanceof SdkLibrary) {
          final SdkLibrary sdk = (SdkLibrary) lib;
          libBuilder.setHomePath(sdk.getHomePath());
          libBuilder.setTypeName(sdk.getTypeName());
          final String additional = sdk.getAdditionalDataXml();
          if (additional != null) {
            libBuilder.setAdditionalDataXml(additional);
          }
          final String version = sdk.getVersion();
          if (version != null) {
            libBuilder.setVersion(version);
          }
        }
        cmdBuilder.addGlobalLibrary(libBuilder.build());
      }
    }

    final String defaultCharset = EncodingManager.getInstance().getDefaultCharsetName();
    if (defaultCharset != null) {
      cmdBuilder.setGlobalEncoding(defaultCharset);
    }

    final String ignoredFilesList = FileTypeManager.getInstance().getIgnoredFilesList();
    cmdBuilder.setIgnoredFilesPatterns(ignoredFilesList);
    return cmdBuilder.build();
  }