/* * SonarLint for Eclipse * Copyright (C) 2015-2017 SonarSource SA * sonarlint@sonarsource.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonarlint.eclipse.core.internal.jobs; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.util.List; import javax.annotation.Nullable; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.jface.text.IDocument; import org.sonarlint.eclipse.core.resource.ISonarLintFile; import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile; /** * Two situations: * - either a IDocument is provided, which mean the file is open in an editor * - if document is <code>null</code> then file is not open but that doesn't mean we can read from FS, since the file might be stored on a remote FS * */ class EclipseInputFile implements ClientInputFile { private final List<PathMatcher> pathMatchersForTests; private final ISonarLintFile file; private final String language; private final IDocument editorDocument; private final Path tempDirectory; private Path filePath; EclipseInputFile(List<PathMatcher> pathMatchersForTests, ISonarLintFile file, Path tempDirectory, @Nullable IDocument editorDocument, @Nullable String language) { this.pathMatchersForTests = pathMatchersForTests; this.file = file; this.tempDirectory = tempDirectory; this.language = language; this.editorDocument = editorDocument; } @Override public String getPath() { if (filePath == null) { initFromFS(file, tempDirectory); } return filePath.toString(); } private synchronized void initFromFS(ISonarLintFile file, Path temporaryDirectory) { IFileStore fileStore; try { fileStore = EFS.getStore(file.getResource().getLocationURI()); File localFile = fileStore.toLocalFile(EFS.NONE, null); if (localFile == null) { // For analyzers to properly work we should ensure the temporary file has a "correct" name, and not a generated one localFile = new File(temporaryDirectory.toFile(), file.getProjectRelativePath()); Files.createDirectories(localFile.getParentFile().toPath()); fileStore.copy(EFS.getStore(localFile.toURI()), EFS.OVERWRITE, null); } filePath = localFile.toPath().toAbsolutePath(); } catch (Exception e) { throw new IllegalStateException("Unable to find path for file " + file, e); } } @Override public boolean isTest() { Path absolutePath = Paths.get(file.getProject().getName()).resolve(file.getProjectRelativePath()); for (PathMatcher matcher : pathMatchersForTests) { if (matcher.matches(absolutePath)) { return true; } } return false; } @Override public String language() { return language; } @Override public Charset getCharset() { return StandardCharsets.UTF_8; } @Override public <G> G getClientObject() { return (G) file; } @Override public String contents() throws IOException { // Prefer to use editor Document when file is already opened in an editor if (editorDocument != null) { return editorDocument.get(); } return file.getDocument().get(); } @Override public InputStream inputStream() throws IOException { return new ByteArrayInputStream(contents().getBytes(getCharset())); } }