public static void createSourceRootIfNotExist(
      @NotNull final String path, @NotNull final Module module) {
    ApplicationManager.getApplication().assertIsDispatchThread();

    final File rootFile = new File(path);
    final boolean created;
    if (!rootFile.exists()) {
      if (!rootFile.mkdirs()) return;
      created = true;
    } else {
      created = false;
    }

    final Project project = module.getProject();
    Module genModule = module;

    final AndroidFacet facet = AndroidFacet.getInstance(genModule);

    if (facet != null && facet.getConfiguration().LIBRARY_PROJECT) {
      removeGenModule(module);
    }

    if (project.isDisposed() || genModule.isDisposed()) {
      return;
    }

    final VirtualFile root;
    if (created) {
      root = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(rootFile);
    } else {
      root = LocalFileSystem.getInstance().findFileByIoFile(rootFile);
    }
    if (root != null) {
      final ModuleRootManager manager = ModuleRootManager.getInstance(genModule);
      unexcludeRootIfNeccessary(root, manager);
      for (VirtualFile existingRoot : manager.getSourceRoots()) {
        if (existingRoot == root) return;
      }
      ApplicationManager.getApplication()
          .runWriteAction(
              new Runnable() {
                public void run() {
                  addSourceRoot(manager, root);
                }
              });
    }
  }
 private static void addLibraryJar(
     final VirtualFile virtualFile,
     final File zipFile,
     final String pluginName,
     final ZipOutputStream zos,
     final Set<String> usedJarNames,
     final ProgressIndicator progressIndicator)
     throws IOException {
   File ioFile = VfsUtil.virtualToIoFile(virtualFile);
   final String jarName = getLibraryJarName(ioFile.getName(), usedJarNames, null);
   ZipUtil.addFileOrDirRecursively(
       zos,
       zipFile,
       ioFile,
       getZipPath(pluginName, jarName),
       createFilter(progressIndicator, null),
       null);
 }
 private static VirtualFile[] getFilesToCheckReadonlyStatus(
     GeneratingCompiler.GenerationItem[] items) {
   List<VirtualFile> filesToCheck = new ArrayList<VirtualFile>();
   for (GeneratingCompiler.GenerationItem item : items) {
     if (item instanceof AndroidAptCompiler.AptGenerationItem) {
       final Set<File> generatedFiles =
           ((AndroidAptCompiler.AptGenerationItem) item).getGeneratedFiles().keySet();
       for (File generatedFile : generatedFiles) {
         if (generatedFile.exists()) {
           VirtualFile generatedVFile =
               LocalFileSystem.getInstance().findFileByIoFile(generatedFile);
           if (generatedVFile != null) {
             filesToCheck.add(generatedVFile);
           }
         }
       }
     }
   }
   return VfsUtil.toVirtualFileArray(filesToCheck);
 }
 private static File jarModulesOutput(
     @NotNull Set<Module> modules,
     @Nullable Manifest manifest,
     final @Nullable String pluginXmlPath)
     throws IOException {
   File jarFile = FileUtil.createTempFile(TEMP_PREFIX, JAR_EXTENSION);
   jarFile.deleteOnExit();
   ZipOutputStream jarPlugin = null;
   try {
     BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(jarFile));
     jarPlugin = manifest != null ? new JarOutputStream(out, manifest) : new JarOutputStream(out);
     final ProgressIndicator progressIndicator =
         ProgressManager.getInstance().getProgressIndicator();
     final Set<String> writtenItemRelativePaths = new HashSet<String>();
     for (Module module : modules) {
       final VirtualFile compilerOutputPath =
           CompilerModuleExtension.getInstance(module).getCompilerOutputPath();
       if (compilerOutputPath == null)
         continue; // pre-condition: output dirs for all modules are up-to-date
       ZipUtil.addDirToZipRecursively(
           jarPlugin,
           jarFile,
           new File(compilerOutputPath.getPath()),
           "",
           createFilter(progressIndicator, FileTypeManager.getInstance()),
           writtenItemRelativePaths);
     }
     if (pluginXmlPath != null) {
       ZipUtil.addFileToZip(
           jarPlugin,
           new File(pluginXmlPath),
           "/META-INF/plugin.xml",
           writtenItemRelativePaths,
           createFilter(progressIndicator, null));
     }
   } finally {
     if (jarPlugin != null) jarPlugin.close();
   }
   return jarFile;
 }
 private static boolean clearReadOnly(final Project project, final File dstFile) {
   //noinspection EmptyCatchBlock
   final URL url;
   try {
     url = dstFile.toURL();
   } catch (MalformedURLException e) {
     return true;
   }
   final VirtualFile vfile = VfsUtil.findFileByURL(url);
   return vfile == null
       || !ReadonlyStatusHandler.getInstance(project)
           .ensureFilesWritable(vfile)
           .hasReadonlyFiles();
 }
 private static void makeAndAddLibraryJar(
     final VirtualFile virtualFile,
     final File zipFile,
     final String pluginName,
     final ZipOutputStream zos,
     final Set<String> usedJarNames,
     final ProgressIndicator progressIndicator,
     final String preferredName)
     throws IOException {
   File libraryJar = FileUtil.createTempFile(TEMP_PREFIX, JAR_EXTENSION);
   libraryJar.deleteOnExit();
   ZipOutputStream jar = null;
   try {
     jar = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(libraryJar)));
     ZipUtil.addFileOrDirRecursively(
         jar,
         libraryJar,
         VfsUtilCore.virtualToIoFile(virtualFile),
         "",
         createFilter(progressIndicator, FileTypeManager.getInstance()),
         null);
   } finally {
     if (jar != null) jar.close();
   }
   final String jarName =
       getLibraryJarName(
           virtualFile.getName() + JAR_EXTENSION,
           usedJarNames,
           preferredName == null ? null : preferredName + JAR_EXTENSION);
   ZipUtil.addFileOrDirRecursively(
       zos,
       zipFile,
       libraryJar,
       getZipPath(pluginName, jarName),
       createFilter(progressIndicator, null),
       null);
 }
  private static void addFileToJar(
      @NotNull JarOutputStream jar,
      @NotNull File file,
      @NotNull File rootDirectory,
      boolean packRClasses)
      throws IOException {

    if (file.isDirectory()) {
      for (File child : file.listFiles()) {
        addFileToJar(jar, child, rootDirectory, packRClasses);
      }
    } else if (file.isFile()) {
      if (!FileUtil.getExtension(file.getName()).equals("class")) {
        return;
      }

      if (!packRClasses && R_PATTERN.matcher(file.getName()).matches()) {
        return;
      }

      final String rootPath = rootDirectory.getAbsolutePath();

      String path = file.getAbsolutePath();
      path = FileUtil.toSystemIndependentName(path.substring(rootPath.length()));
      if (path.charAt(0) == '/') {
        path = path.substring(1);
      }

      final JarEntry entry = new JarEntry(path);
      entry.setTime(file.lastModified());
      jar.putNextEntry(entry);

      BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
      try {
        final byte[] buffer = new byte[1024];
        int count;
        while ((count = bis.read(buffer)) != -1) {
          jar.write(buffer, 0, count);
        }
        jar.closeEntry();
      } finally {
        bis.close();
      }
    }
  }
  public static void removeDuplicatingClasses(
      final Module module,
      @NotNull final String packageName,
      @NotNull String className,
      @Nullable File classFile,
      String sourceRootPath) {
    if (sourceRootPath == null) {
      return;
    }
    VirtualFile sourceRoot = LocalFileSystem.getInstance().findFileByPath(sourceRootPath);
    if (sourceRoot == null) {
      return;
    }
    final Project project = module.getProject();
    final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
    final String interfaceQualifiedName = packageName + '.' + className;
    PsiClass[] classes =
        facade.findClasses(interfaceQualifiedName, GlobalSearchScope.moduleScope(module));
    final ProjectFileIndex projectFileIndex =
        ProjectRootManager.getInstance(project).getFileIndex();
    for (PsiClass c : classes) {
      PsiFile psiFile = c.getContainingFile();
      if (className.equals(FileUtil.getNameWithoutExtension(psiFile.getName()))) {
        VirtualFile virtualFile = psiFile.getVirtualFile();
        if (virtualFile != null
            && projectFileIndex.getSourceRootForFile(virtualFile) == sourceRoot) {
          final String path = virtualFile.getPath();
          File f = new File(path);

          try {
            f = f.getCanonicalFile();
            classFile = classFile != null ? classFile.getCanonicalFile() : null;
            if (f != null && !f.equals(classFile) && f.exists()) {
              if (f.delete()) {
                virtualFile.refresh(true, false);
              } else {
                ApplicationManager.getApplication()
                    .invokeLater(
                        new Runnable() {
                          public void run() {
                            Messages.showErrorDialog(
                                project, "Can't delete file " + path, CommonBundle.getErrorTitle());
                          }
                        },
                        project.getDisposed());
              }
            }
          } catch (IOException e) {
            LOG.info(e);
          }
        }
      }
    }
  }
  public static void packClassFilesIntoJar(
      @NotNull String[] firstPackageDirPaths,
      @NotNull String[] libFirstPackageDirPaths,
      @NotNull File jarFile)
      throws IOException {
    final JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile));
    try {
      for (String path : firstPackageDirPaths) {
        final File firstPackageDir = new File(path);
        if (firstPackageDir.exists()) {
          addFileToJar(jos, firstPackageDir, firstPackageDir.getParentFile(), true);
        }
      }

      for (String path : libFirstPackageDirPaths) {
        final File firstPackageDir = new File(path);
        if (firstPackageDir.exists()) {
          addFileToJar(jos, firstPackageDir, firstPackageDir.getParentFile(), false);
        }
      }
    } finally {
      jos.close();
    }
  }
  public static boolean doPrepare(
      final Module module, final List<String> errorMessages, final List<String> successMessages) {
    final String pluginName = module.getName();
    final String defaultPath =
        new File(module.getModuleFilePath()).getParent() + File.separator + pluginName;
    final HashSet<Module> modules = new HashSet<Module>();
    PluginBuildUtil.getDependencies(module, modules);
    modules.add(module);
    final Set<Library> libs = new HashSet<Library>();
    for (Module dep : modules) {
      PluginBuildUtil.getLibraries(dep, libs);
    }

    final Map<Module, String> jpsModules = collectJpsPluginModules(module);
    modules.removeAll(jpsModules.keySet());

    final boolean isZip = !libs.isEmpty() || !jpsModules.isEmpty();
    final String oldPath = defaultPath + (isZip ? JAR_EXTENSION : ZIP_EXTENSION);
    final File oldFile = new File(oldPath);
    if (oldFile.exists()) {
      if (Messages.showYesNoDialog(
              module.getProject(),
              DevKitBundle.message("suggest.to.delete", oldPath),
              DevKitBundle.message("info.message"),
              Messages.getInformationIcon())
          == Messages.YES) {
        FileUtil.delete(oldFile);
      }
    }

    final String dstPath = defaultPath + (isZip ? ZIP_EXTENSION : JAR_EXTENSION);
    final File dstFile = new File(dstPath);
    return clearReadOnly(module.getProject(), dstFile)
        && ProgressManager.getInstance()
            .runProcessWithProgressSynchronously(
                new Runnable() {
                  public void run() {

                    final ProgressIndicator progressIndicator =
                        ProgressManager.getInstance().getProgressIndicator();
                    if (progressIndicator != null) {
                      progressIndicator.setText(
                          DevKitBundle.message("prepare.for.deployment.common"));
                      progressIndicator.setIndeterminate(true);
                    }
                    try {
                      File jarFile = preparePluginsJar(module, modules);
                      if (isZip) {
                        processLibrariesAndJpsPlugins(
                            jarFile, dstFile, pluginName, libs, jpsModules, progressIndicator);
                      } else {
                        FileUtil.copy(jarFile, dstFile);
                      }
                      LocalFileSystem.getInstance()
                          .refreshIoFiles(Collections.singleton(dstFile), true, false, null);
                      successMessages.add(
                          DevKitBundle.message(
                              "saved.message", isZip ? 1 : 2, pluginName, dstPath));
                    } catch (final IOException e) {
                      errorMessages.add(e.getMessage() + "\n(" + dstPath + ")");
                    }
                  }
                },
                DevKitBundle.message("prepare.for.deployment", pluginName),
                true,
                module.getProject());
  }
  @Nullable
  public static String findResourcesCacheDirectory(
      @NotNull Module module, boolean createIfNotFound, @Nullable CompileContext context) {
    final Project project = module.getProject();

    final CompilerProjectExtension extension = CompilerProjectExtension.getInstance(project);
    if (extension == null) {
      if (context != null) {
        context.addMessage(
            CompilerMessageCategory.ERROR,
            "Cannot get compiler settings for project " + project.getName(),
            null,
            -1,
            -1);
      }
      return null;
    }

    final String projectOutputDirUrl = extension.getCompilerOutputUrl();
    if (projectOutputDirUrl == null) {
      if (context != null) {
        context.addMessage(
            CompilerMessageCategory.ERROR,
            "Cannot find output directory for project " + project.getName(),
            null,
            -1,
            -1);
      }
      return null;
    }

    final String pngCacheDirPath =
        VfsUtil.urlToPath(projectOutputDirUrl)
            + '/'
            + RESOURCES_CACHE_DIR_NAME
            + '/'
            + module.getName();
    final String pngCacheDirOsPath = FileUtil.toSystemDependentName(pngCacheDirPath);

    final File pngCacheDir = new File(pngCacheDirOsPath);
    if (pngCacheDir.exists()) {
      if (pngCacheDir.isDirectory()) {
        return pngCacheDirOsPath;
      } else {
        if (context != null) {
          context.addMessage(
              CompilerMessageCategory.ERROR,
              "Cannot create directory " + pngCacheDirOsPath + " because file already exists",
              null,
              -1,
              -1);
        }
        return null;
      }
    }

    if (!createIfNotFound) {
      return null;
    }

    if (!pngCacheDir.mkdirs()) {
      if (context != null) {
        context.addMessage(
            CompilerMessageCategory.ERROR,
            "Cannot create directory " + pngCacheDirOsPath,
            null,
            -1,
            -1);
      }
      return null;
    }

    return pngCacheDirOsPath;
  }