Package org.infernus.idea.checkstyle.util

Source Code of org.infernus.idea.checkstyle.util.ScannableFile

package org.infernus.idea.checkstyle.util;

import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiJavaFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import org.jetbrains.annotations.NotNull;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.UUID;
import java.util.regex.Matcher;

/**
* A representation of a file able to be scanned.
*/
public class ScannableFile {
    private static final String TEMPFILE_DIR_PREFIX = "csi-";

    private final File realFile;
    private final File baseTempDir;

    /**
     * Create a new scannable file from a PSI file.
     * <p/>
     * If required this will create a temporary copy of the file.
     *
     * @param psiFile the psiFile to create the file from.
     * @param module  the module the file belongs to.
     * @throws IOException if file creation is required and fails.
     */
    public ScannableFile(@NotNull final PsiFile psiFile,
                         @NotNull final Module module)
            throws IOException {
        if (!existsOnFilesystem(psiFile)
                || documentIsModifiedAndUnsaved(psiFile.getVirtualFile())) {
            baseTempDir = prepareBaseTmpDir();
            realFile = createTemporaryFileFor(psiFile, module, baseTempDir);

        } else {
            baseTempDir = null;
            realFile = new File(pathOf(psiFile));
        }
    }

    private String pathOf(@NotNull final PsiFile psiFile) {
        if (psiFile.getVirtualFile() != null) {
            return psiFile.getVirtualFile().getPath();
        }
        throw new IllegalStateException("PSIFile does not have associated virtual file: " + psiFile);
    }

    private File createTemporaryFileFor(@NotNull final PsiFile psiFile,
                                        @NotNull final Module module,
                                        @NotNull final File tempDir)
            throws IOException {
        final File temporaryFile = new File(parentDirFor(psiFile, module, tempDir), psiFile.getName());
        temporaryFile.deleteOnExit();

        writeContentsToFile(psiFile, temporaryFile);

        return temporaryFile;
    }

    private File parentDirFor(@NotNull final PsiFile psiFile,
                              @NotNull final Module module,
                              @NotNull final File baseTmpDir) {
        File tmpDirForFile = null;

        if (psiFile.getParent() != null) {
            final String parentUrl = psiFile.getParent().getVirtualFile().getUrl();
            for (String moduleSourceRoot : ModuleRootManager.getInstance(module).getContentRootUrls()) {
                if (parentUrl.startsWith(moduleSourceRoot)) {
                    tmpDirForFile = new File(baseTmpDir.getAbsolutePath() + parentUrl.substring(moduleSourceRoot.length()));
                    break;
                }
            }
        }

        if (tmpDirForFile == null) {
            if (psiFile instanceof PsiJavaFile) {
                final String packageName = ((PsiJavaFile) psiFile).getPackageName();
                final String packagePath = packageName.replaceAll(
                        "\\.", Matcher.quoteReplacement(File.separator));

                tmpDirForFile = new File(baseTmpDir.getAbsolutePath() + File.separator + packagePath);
            } else {
                tmpDirForFile = baseTmpDir;
            }
        }

        //noinspection ResultOfMethodCallIgnored
        tmpDirForFile.mkdirs();

        return tmpDirForFile;
    }

    private File prepareBaseTmpDir() {
        final File baseTmpDir = new File(System.getProperty("java.io.tmpdir"),
                TEMPFILE_DIR_PREFIX + UUID.randomUUID().toString());
        baseTmpDir.deleteOnExit();
        return baseTmpDir;
    }

    private boolean existsOnFilesystem(@NotNull final PsiFile psiFile) {
        final VirtualFile virtualFile = psiFile.getVirtualFile();
        return virtualFile != null
                && LocalFileSystem.getInstance().exists(virtualFile);
    }

    private boolean documentIsModifiedAndUnsaved(final VirtualFile virtualFile) {
        if (virtualFile == null) {
            return false;
        }
        final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
        if (fileDocumentManager.isFileModified(virtualFile)) {
            final Document document = fileDocumentManager.getDocument(virtualFile);
            if (document != null) {
                return fileDocumentManager.isDocumentUnsaved(document);
            }
        }
        return false;
    }

    private void writeContentsToFile(final PsiFile psiFile,
                                     final File outFile)
            throws IOException {
        final CodeStyleSettings codeStyleSettings
                = CodeStyleSettingsManager.getSettings(psiFile.getProject());

        final BufferedWriter tempFileOut = new BufferedWriter(
                new FileWriter(outFile));
        for (final char character : psiFile.getText().toCharArray()) {
            if (character == '\n') { // IDEA uses \n internally
                tempFileOut.write(codeStyleSettings.getLineSeparator());
            } else {
                tempFileOut.write(character);
            }
        }
        tempFileOut.flush();
        tempFileOut.close();
    }

    public File getFile() {
        return realFile;
    }

    /**
     * Delete the file if appropriate.
     */
    public void deleteIfRequired() {
        if (baseTempDir != null
                && baseTempDir.getName().startsWith(TEMPFILE_DIR_PREFIX)) {
            delete(baseTempDir);
        }
    }

    private void delete(@NotNull final File file) {
        if (!file.exists()) {
            return;
        }

        if (file.isDirectory()) {
            final File[] files = file.listFiles();
            if (files != null) {
                for (File child : files) {
                    delete(child);
                }
            }
        }

        //noinspection ResultOfMethodCallIgnored
        file.delete();
    }

    public String getAbsolutePath() {
        return realFile.getAbsolutePath();
    }

    @Override
    public String toString() {
        return String.format("[ScannableFile: file=%s; temporary=%s]", realFile.toString(), baseTempDir != null);
    }
}
TOP

Related Classes of org.infernus.idea.checkstyle.util.ScannableFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.