001/*
002 * SonarQube
003 * Copyright (C) 2009-2016 SonarSource SA
004 * mailto:contact AT sonarsource DOT com
005 *
006 * This program 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 * This program 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 */
020package org.sonar.api.batch.fs;
021
022import java.io.File;
023import java.io.IOException;
024import java.io.InputStream;
025import java.nio.charset.Charset;
026import java.nio.file.Files;
027import java.nio.file.Path;
028import javax.annotation.CheckForNull;
029import org.sonar.api.batch.fs.internal.DefaultInputFile;
030
031/**
032 * This layer over {@link java.io.File} adds information for code analyzers.
033 * For unit testing purpose you can create some {@link DefaultInputFile} and initialize
034 * all fields using 
035 * 
036 * <pre>
037 *   new DefaultInputFile("moduleKey", "relative/path/from/module/baseDir.java")
038 *     .setModuleBaseDir(path)
039 *     .initMetadata(new FileMetadata().readMetadata(someReader));
040 * </pre>
041 *
042 * @since 4.2
043 */
044public interface InputFile extends InputPath {
045
046  enum Type {
047    MAIN, TEST
048  }
049
050  /** 
051   * Status regarding previous analysis
052   */
053  enum Status {
054    SAME, CHANGED, ADDED
055  }
056
057  /**
058   * Path relative to module base directory. Path is unique and identifies file
059   * within given <code>{@link FileSystem}</code>. File separator is the forward
060   * slash ('/'), even on Microsoft Windows.
061   * <br>
062   * Returns <code>src/main/java/com/Foo.java</code> if module base dir is
063   * <code>/path/to/module</code> and if file is
064   * <code>/path/to/module/src/main/java/com/Foo.java</code>.
065   * <br>
066   * Relative path is not null and is normalized ('foo/../foo' is replaced by 'foo').
067   */
068  @Override
069  String relativePath();
070
071  /**
072   * Normalized absolute path. File separator is forward slash ('/'), even on Microsoft Windows.
073   * <br>
074   * This is not canonical path. Symbolic links are not resolved. For example if /project/src links
075   * to /tmp/src and basedir is /project, then this method returns /project/src/index.php. Use
076   * {@code file().getCanonicalPath()} to resolve symbolic link.
077   */
078  @Override
079  String absolutePath();
080
081  /**
082   * The underlying absolute {@link java.io.File}. It should not be used to read the file in the filesystem.
083   * @see #contents()
084   * @see #inputStream()
085   */
086  @Override
087  File file();
088
089  /**
090   * The underlying absolute {@link Path}.
091   * It should not be used to read the file in the filesystem.
092   * @see #contents()
093   * @see #inputStream()
094   * @since 5.1
095   */
096  @Override
097  Path path();
098
099  /**
100   * Language, for example "java" or "php". Can be null if indexation of all files is enabled and no language claims to support the file.
101   */
102  @CheckForNull
103  String language();
104
105  /**
106   * Does it contain main or test code ?
107   */
108  Type type();
109
110  /**
111   * Creates a stream of the file's contents. Depending on the runtime context, the source might be a file in a physical or virtual filesystem.
112   * Typically, it won't be buffered. <b>The stream must be closed by the caller</b>.
113   * Note that there is a default implementation.
114   * @since 6.2
115   */
116  default InputStream inputStream() throws IOException {
117    return Files.newInputStream(path());
118  }
119
120  /**
121   * Fetches the entire contents of the file, decoding with the {@link #charset}.
122   * Note that there is a default implementation.
123   * @since 6.2
124   */
125  default String contents() throws IOException {
126    return new String(Files.readAllBytes(path()), charset());
127  }
128
129  /**
130   * Status regarding previous analysis
131   */
132  Status status();
133
134  /**
135   * Number of physical lines. This method supports all end-of-line characters. Formula is (number of line break + 1). 
136   * <p>
137   * Returns 1 if the file is empty.
138   * <br> 
139   * Returns 2 for <tt>foo\nbar</tt>. 
140   * <br>
141   * Returns 3 for <tt>foo\nbar\n</tt>.
142   */
143  int lines();
144
145  /**
146   * Check if the file content is empty (ignore potential BOM).
147   * @since 5.2
148   */
149  boolean isEmpty();
150
151  /**
152   * Returns a {@link TextPointer} in the given file.
153   * @param line Line of the pointer. Start at 1.
154   * @param lineOffset Offset in the line. Start at 0.
155   * @throws IllegalArgumentException if line or offset is not valid for the given file.
156   * @since 5.2
157   */
158  TextPointer newPointer(int line, int lineOffset);
159
160  /**
161   * Returns a {@link TextRange} in the given file.
162   * @param start start pointer
163   * @param end end pointer
164   * @throws IllegalArgumentException if start or stop pointers are not valid for the given file.
165   * @since 5.2
166   */
167  TextRange newRange(TextPointer start, TextPointer end);
168
169  /**
170   * Returns a {@link TextRange} in the given file.
171   * <ul>
172   * <li><code>newRange(1, 0, 1, 1)</code> selects the first character at line 1</li>
173   * <li><code>newRange(1, 0, 1, 10)</code> selects the 10 first characters at line 1</li>
174   * </ul>
175   * @throws IllegalArgumentException if start or stop positions are not valid for the given file.
176   * @since 5.2
177   */
178  TextRange newRange(int startLine, int startLineOffset, int endLine, int endLineOffset);
179
180  /**
181   * Returns a {@link TextRange} in the given file that select the full line.
182   * @param line Start at 1.
183   * @throws IllegalArgumentException if line is not valid for the given file.
184   * @since 5.2
185   */
186  TextRange selectLine(int line);
187
188  /**
189   * Charset to be used to decode this specific file.
190   * @since 6.0
191   */
192  Charset charset();
193}