blob: 49e5946035eb0a87201ed8b2f5f214876482c9b8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.php.project.api;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.modules.php.project.classpath.CommonPhpSourcePath;
import org.netbeans.modules.php.project.classpath.IncludePathClassPathProvider;
import org.netbeans.modules.php.project.classpath.PhpSourcePathImplementation;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.modules.InstalledFileLocator;
import org.openide.util.Parameters;
/**
* @author Tomas Mysik
* @since 2.1
*/
public final class PhpSourcePath {
public static final String BOOT_CP = "classpath/php-boot"; //NOI18N
/**
* @since 2.71
*/
public static final String PROJECT_BOOT_CP = "classpath/php-project-boot"; //NOI18N
public static final String SOURCE_CP = "classpath/php-source"; //NOI18N
private static final DefaultPhpSourcePath DEFAULT_PHP_SOURCE_PATH = new DefaultPhpSourcePath();
// @GuardedBy(PhpSourcePath.class)
private static FileObject phpStubsFolder = null;
/**
* Possible types of a file.
*/
public static enum FileType {
/** Internal files (signature files). */
INTERNAL,
/** PHP include path. */
INCLUDE,
/** Project sources. */
SOURCE,
/** Project test sources. */
TEST,
/** Unknown file type. */
UNKNOWN,
}
private PhpSourcePath() {
}
/**
* Get the file type for the given file object.
* @param file the input file.
* @return the file type for the given file object.
* @see FileType
*/
public static FileType getFileType(FileObject file) {
Parameters.notNull("file", file);
// #221482, #165738
// check internal files (perhaps the most common use case)
if (org.netbeans.modules.php.project.util.PhpProjectUtils.isInternalFile(file)) {
return FileType.INTERNAL;
}
// then, check sources (typical use-case)
PhpSourcePathImplementation phpSourcePath = getPhpSourcePathForProjectFile(file);
if (phpSourcePath != null) {
return phpSourcePath.getFileType(file);
}
// lastly, check classpath for project's specific include path (known to be very slow)
FileType fileType = getFileTypeFromIncludeClassPath(file);
if (fileType != null) {
return fileType;
}
// perhaps a file without a project or a file on global include path
// in fact, this is not supported by the editor yet (model does not work for a file without a project)
return DEFAULT_PHP_SOURCE_PATH.getFileType(file);
}
/**
* Get list of folders, where asignatures file for PHP runtime are.
* These files are also preindexed.
* @return list of folders
*/
public static synchronized List<FileObject> getPreindexedFolders() {
if (phpStubsFolder == null) {
// Core classes: Stubs generated for the "builtin" php runtime and extenstions.
File clusterFile = InstalledFileLocator.getDefault().locate("docs/phpsigfiles.zip", "org.netbeans.modules.php.project", true); //NOI18N
if (clusterFile != null) {
FileObject root = FileUtil.getArchiveRoot(FileUtil.toFileObject(clusterFile));
phpStubsFolder = root.getFileObject("phpstubs/phpruntime"); //NOI18N
}
}
if (phpStubsFolder == null) {
// during tests
return Collections.emptyList();
}
return Collections.singletonList(phpStubsFolder);
}
/**
* Get all the possible path roots from PHP include path for the given file. If the file equals <code>null</code> then
* just global PHP include path is returned.
* @param file a file which could belong to a project or <code>null</code> for gettting global PHP include path.
* @return all the possible path roots from PHP include path.
*/
public static List<FileObject> getIncludePath(FileObject file) {
if (file == null) {
return DEFAULT_PHP_SOURCE_PATH.getIncludePath();
}
PhpSourcePathImplementation phpSourcePath = getPhpSourcePathForProjectFile(file);
if (phpSourcePath != null) {
return phpSourcePath.getIncludePath();
}
return DEFAULT_PHP_SOURCE_PATH.getIncludePath();
}
/**
* Resolve absolute path for the given file name. The order is the given directory then PHP include path.
* @param directory the directory to which the PHP <code>include()</code> or <code>require()</code> functions
* could be resolved. Typically the directory containing the given script.
* @param fileName a file name or a relative path delimited by '/'.
* @return resolved file path or <code>null</code> if the given file is not found.
*/
public static FileObject resolveFile(FileObject directory, String fileName) {
Parameters.notNull("directory", directory);
Parameters.notNull("fileName", fileName);
if (!directory.isFolder()) {
throw new IllegalArgumentException("valid directory needed");
}
PhpSourcePathImplementation phpSourcePath = getPhpSourcePathForProjectFile(directory);
if (phpSourcePath != null) {
return phpSourcePath.resolveFile(directory, fileName);
}
return DEFAULT_PHP_SOURCE_PATH.resolveFile(directory, fileName);
}
private static PhpSourcePathImplementation getPhpSourcePathForProjectFile(FileObject file) {
Project project = FileOwnerQuery.getOwner(file);
if (project == null) {
return null;
}
PhpSourcePathImplementation phpSourcePath = project.getLookup().lookup(PhpSourcePathImplementation.class);
// XXX disabled because of runtime.php underneath nbbuild directory
//assert phpSourcePath != null : "Not PHP project (interface PhpSourcePath not found in lookup)! [" + project + "]";
return phpSourcePath;
}
private static FileType getFileTypeFromIncludeClassPath(FileObject file) {
// now, check include path of opened projects
ClassPath classPath = IncludePathClassPathProvider.findProjectIncludePath(file);
if (classPath != null && classPath.contains(file)) {
// internal?
if (org.netbeans.modules.php.project.util.PhpProjectUtils.isInternalFile(file)) {
return FileType.INTERNAL;
}
// include
return FileType.INCLUDE;
}
return null;
}
// PhpSourcePathImplementation implementation for file which does not belong to any project
private static class DefaultPhpSourcePath implements org.netbeans.modules.php.project.classpath.PhpSourcePathImplementation {
@Override
public FileType getFileType(FileObject file) {
if (org.netbeans.modules.php.project.util.PhpProjectUtils.isInternalFile(file)) {
return FileType.INTERNAL;
}
for (FileObject dir : getPlatformPath()) {
if (dir.equals(file) || FileUtil.isParentOf(dir, file)) {
return FileType.INCLUDE;
}
}
return FileType.UNKNOWN;
}
@Override
public List<FileObject> getIncludePath() {
return new ArrayList<>(getPlatformPath());
}
@Override
public FileObject resolveFile(FileObject directory, String fileName) {
FileObject resolved = directory.getFileObject(fileName);
if (resolved != null) {
return resolved;
}
for (FileObject dir : getPlatformPath()) {
resolved = dir.getFileObject(fileName);
if (resolved != null) {
return resolved;
}
}
return null;
}
// XXX cache?
private List<FileObject> getPlatformPath() {
String[] paths = PhpOptions.getInstance().getPhpGlobalIncludePathAsArray();
List<FileObject> internalPath = CommonPhpSourcePath.getInternalPath();
List<FileObject> dirs = new ArrayList<>(paths.length + internalPath.size());
dirs.addAll(internalPath);
for (String path : paths) {
FileObject resolvedFile = FileUtil.toFileObject(FileUtil.normalizeFile(new File(path)));
if (resolvedFile != null) { // XXX check isValid() as well?
dirs.add(resolvedFile);
}
}
return dirs;
}
}
}