001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2014 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * SonarQube is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * SonarQube is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public License
017     * along with this program; if not, write to the Free Software Foundation,
018     * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019     */
020    package org.sonar.batch.scan.filesystem;
021    
022    import com.google.common.collect.Iterables;
023    import com.google.common.collect.Lists;
024    import org.apache.commons.io.FileUtils;
025    import org.apache.commons.lang.CharEncoding;
026    import org.apache.maven.project.MavenProject;
027    import org.sonar.api.batch.fs.FilePredicate;
028    import org.sonar.api.resources.InputFile;
029    import org.sonar.api.resources.Java;
030    import org.sonar.api.resources.Language;
031    import org.sonar.api.resources.Project;
032    import org.sonar.api.resources.ProjectFileSystem;
033    import org.sonar.api.resources.Resource;
034    import org.sonar.api.scan.filesystem.PathResolver;
035    import org.sonar.api.utils.SonarException;
036    
037    import javax.annotation.Nullable;
038    import java.io.File;
039    import java.io.IOException;
040    import java.nio.charset.Charset;
041    import java.util.Arrays;
042    import java.util.List;
043    
044    /**
045     * Adapter for keeping the backward-compatibility of the deprecated component {@link org.sonar.api.resources.ProjectFileSystem}
046     *
047     * @since 3.5
048     */
049    public class ProjectFileSystemAdapter implements ProjectFileSystem {
050    
051      private final DefaultModuleFileSystem target;
052      private final PathResolver pathResolver = new PathResolver();
053      private final MavenProject pom;
054    
055      public ProjectFileSystemAdapter(DefaultModuleFileSystem target, Project project, @Nullable MavenProject pom) {
056        this.target = target;
057        this.pom = pom;
058    
059        // previously MavenProjectBuilder was responsible for creation of ProjectFileSystem
060        project.setFileSystem(this);
061      }
062    
063      public ProjectFileSystemAdapter(DefaultModuleFileSystem target, Project project) {
064        this(target, project, null);
065      }
066    
067      public void start() {
068        // used to avoid NPE in Project#getFileSystem()
069      }
070    
071      public Charset getSourceCharset() {
072        return target.sourceCharset();
073      }
074    
075      public File getBasedir() {
076        return target.baseDir();
077      }
078    
079      public File getBuildDir() {
080        File dir = target.buildDir();
081        if (dir == null) {
082          // emulate build dir to keep backward-compatibility
083          dir = new File(getSonarWorkingDirectory(), "build");
084        }
085        return dir;
086      }
087    
088      public File getBuildOutputDir() {
089        File dir = Iterables.getFirst(target.binaryDirs(), null);
090        if (dir == null) {
091          // emulate binary dir
092          dir = new File(getBuildDir(), "classes");
093        }
094    
095        return dir;
096      }
097    
098      public List<File> getSourceDirs() {
099        return target.sourceDirs();
100      }
101    
102      public ProjectFileSystem addSourceDir(File dir) {
103        target.addSourceDir(dir);
104        return this;
105      }
106    
107      public List<File> getTestDirs() {
108        return target.testDirs();
109      }
110    
111      public ProjectFileSystem addTestDir(File dir) {
112        target.addTestDir(dir);
113        return this;
114      }
115    
116      public File getReportOutputDir() {
117        if (pom != null) {
118          return resolvePath(pom.getReporting().getOutputDirectory());
119        }
120        // emulate Maven report output dir
121        return new File(getBuildDir(), "site");
122      }
123    
124      public File getSonarWorkingDirectory() {
125        return target.workingDir();
126      }
127    
128      public File resolvePath(String path) {
129        File file = new File(path);
130        if (!file.isAbsolute()) {
131          try {
132            file = new File(getBasedir(), path).getCanonicalFile();
133          } catch (IOException e) {
134            throw new SonarException("Unable to resolve path '" + path + "'", e);
135          }
136        }
137        return file;
138      }
139    
140      public List<File> getSourceFiles(Language... langs) {
141        return Lists.newArrayList(target.files(target.predicates().and(
142          target.predicates().hasType(org.sonar.api.batch.fs.InputFile.Type.MAIN),
143          newHasLanguagesPredicate(langs))));
144      }
145    
146      public List<File> getJavaSourceFiles() {
147        return getSourceFiles(Java.INSTANCE);
148      }
149    
150      public boolean hasJavaSourceFiles() {
151        return !getJavaSourceFiles().isEmpty();
152      }
153    
154      public List<File> getTestFiles(Language... langs) {
155        return Lists.newArrayList(target.files(target.predicates().and(
156          target.predicates().hasType(org.sonar.api.batch.fs.InputFile.Type.TEST),
157          newHasLanguagesPredicate(langs))));
158      }
159    
160      public boolean hasTestFiles(Language lang) {
161        return target.hasFiles(target.predicates().and(
162          target.predicates().hasType(org.sonar.api.batch.fs.InputFile.Type.TEST),
163          target.predicates().hasLanguage(lang.getKey())));
164      }
165    
166      public File writeToWorkingDirectory(String content, String fileName) throws IOException {
167        File file = new File(target.workingDir(), fileName);
168        FileUtils.writeStringToFile(file, content, CharEncoding.UTF_8);
169        return file;
170      }
171    
172      public File getFileFromBuildDirectory(String filename) {
173        File file = new File(getBuildDir(), filename);
174        return file.exists() ? file : null;
175      }
176    
177      public Resource toResource(File file) {
178        if (file == null || !file.exists()) {
179          return null;
180        }
181        String relativePath = pathResolver.relativePath(getBasedir(), file);
182        if (relativePath == null) {
183          return null;
184        }
185        return file.isFile() ? org.sonar.api.resources.File.create(relativePath) : org.sonar.api.resources.Directory.create(relativePath);
186      }
187    
188      public List<InputFile> mainFiles(String... langs) {
189        return Lists.newArrayList((Iterable) target.inputFiles(target.predicates().and(
190          target.predicates().hasType(org.sonar.api.batch.fs.InputFile.Type.MAIN),
191          target.predicates().hasLanguages(Arrays.asList(langs))
192        )));
193    
194      }
195    
196      public List<InputFile> testFiles(String... langs) {
197        return Lists.newArrayList((Iterable) target.inputFiles(target.predicates().and(
198          target.predicates().hasType(org.sonar.api.batch.fs.InputFile.Type.TEST),
199          target.predicates().hasLanguages(Arrays.asList(langs))
200        )));
201      }
202    
203      private FilePredicate newHasLanguagesPredicate(Language... languages) {
204        List<FilePredicate> list = Lists.newArrayList();
205        for (Language language : languages) {
206          list.add(target.predicates().hasLanguage(language.getKey()));
207        }
208        return target.predicates().or(list);
209      }
210    }