blob: fc3b0708d383bdcd150b76c8d01cd6567dd79f63 [file] [log] [blame]
package org.jetbrains.plugins.gradle.util;
import com.intellij.ide.actions.OpenProjectFileChooserDescriptor;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileTypeDescriptor;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.Stack;
import org.gradle.tooling.model.GradleProject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.util.Arrays;
import java.util.Properties;
/**
* Holds miscellaneous utility methods.
*
* @author Denis Zhdanov
* @since 8/25/11 1:19 PM
*/
public class GradleUtil {
private static final String WRAPPER_VERSION_PROPERTY_KEY = "distributionUrl";
private static final String LAST_USED_GRADLE_HOME_KEY = "last.used.gradle.home";
private GradleUtil() {
}
/**
* Allows to retrieve file chooser descriptor that filters gradle scripts.
* <p/>
* <b>Note:</b> we want to fall back to the standard {@link FileTypeDescriptor} when dedicated gradle file type
* is introduced (it's processed as groovy file at the moment). We use open project descriptor here in order to show
* custom gradle icon at the file chooser ({@link icons.GradleIcons#Gradle}, is used at the file chooser dialog via
* the dedicated gradle project open processor).
*/
@NotNull
public static FileChooserDescriptor getGradleProjectFileChooserDescriptor() {
return DescriptorHolder.GRADLE_BUILD_FILE_CHOOSER_DESCRIPTOR;
}
@NotNull
public static FileChooserDescriptor getGradleHomeFileChooserDescriptor() {
return DescriptorHolder.GRADLE_HOME_FILE_CHOOSER_DESCRIPTOR;
}
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
public static boolean isGradleWrapperDefined(@Nullable String gradleProjectPath) {
return !StringUtil.isEmpty(getWrapperDistribution(gradleProjectPath));
}
/**
* Tries to parse what gradle version should be used with gradle wrapper for the gradle project located at the given path.
*
* @param gradleProjectPath target gradle project config's (*.gradle) path or config file's directory path.
* @return gradle version should be used with gradle wrapper for the gradle project located at the given path
* if any; <code>null</code> otherwise
*/
@Nullable
public static String getWrapperDistribution(@Nullable String gradleProjectPath) {
if (gradleProjectPath == null) {
return null;
}
File file = new File(gradleProjectPath);
// There is a possible case that given path points to a gradle script (*.gradle) but it's also possible that
// it references script's directory. We want to provide flexibility here.
File gradleDir;
if (file.isFile()) {
gradleDir = new File(file.getParentFile(), "gradle");
}
else {
gradleDir = new File(file, "gradle");
}
if (!gradleDir.isDirectory()) {
return null;
}
File wrapperDir = new File(gradleDir, "wrapper");
if (!wrapperDir.isDirectory()) {
return null;
}
File[] candidates = wrapperDir.listFiles(new FileFilter() {
@Override
public boolean accept(File candidate) {
return candidate.isFile() && candidate.getName().endsWith(".properties");
}
});
if (candidates == null) {
GradleLog.LOG.warn("No *.properties file is found at the gradle wrapper directory " + wrapperDir.getAbsolutePath());
return null;
}
else if (candidates.length != 1) {
GradleLog.LOG.warn(String.format(
"%d *.properties files instead of one have been found at the wrapper directory (%s): %s",
candidates.length, wrapperDir.getAbsolutePath(), Arrays.toString(candidates)
));
return null;
}
Properties props = new Properties();
BufferedReader reader = null;
try {
//noinspection IOResourceOpenedButNotSafelyClosed
reader = new BufferedReader(new FileReader(candidates[0]));
props.load(reader);
String distribution = props.getProperty(WRAPPER_VERSION_PROPERTY_KEY);
if (StringUtil.isEmpty(distribution)) {
return null;
}
String shortName = StringUtil.getShortName(distribution, '/');
return StringUtil.trimEnd(shortName, ".zip");
}
catch (IOException e) {
GradleLog.LOG.warn(
String.format("I/O exception on reading gradle wrapper properties file at '%s'", candidates[0].getAbsolutePath()),
e
);
}
finally {
if (reader != null) {
try {
reader.close();
}
catch (IOException e) {
// Ignore
}
}
}
return null;
}
/**
* We use this class in order to avoid static initialisation of the wrapped object - it loads number of pico container-based
* dependencies that are unavailable to the slave gradle project, so, we don't want to get unexpected NPE there.
*/
private static class DescriptorHolder {
public static final FileChooserDescriptor GRADLE_BUILD_FILE_CHOOSER_DESCRIPTOR = new OpenProjectFileChooserDescriptor(true) {
@Override
public boolean isFileSelectable(VirtualFile file) {
return file.getName().endsWith(GradleConstants.EXTENSION);
}
@Override
public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
if (!super.isFileVisible(file, showHiddenFiles)) {
return false;
}
return file.isDirectory() || file.getName().endsWith(GradleConstants.EXTENSION);
}
};
public static final FileChooserDescriptor GRADLE_HOME_FILE_CHOOSER_DESCRIPTOR
= new FileChooserDescriptor(false, true, false, false, false, false);
}
/**
* Allows to build file system path to the target gradle sub-project given the root project path.
*
* @param subProject target sub-project which config path we're interested in
* @param rootProjectPath path to root project's directory which contains 'build.gradle'
* @return path to the given sub-project's directory which contains 'build.gradle'
*/
@NotNull
public static String getConfigPath(@NotNull GradleProject subProject, @NotNull String rootProjectPath) {
File rootProjectParent = new File(rootProjectPath).getParentFile();
StringBuilder buffer = new StringBuilder(FileUtil.toCanonicalPath(rootProjectParent.getAbsolutePath()));
Stack<String> stack = ContainerUtilRt.newStack();
for (GradleProject p = subProject; p != null; p = p.getParent()) {
stack.push(p.getName());
}
while (!stack.isEmpty()) {
buffer.append(ExternalSystemConstants.PATH_SEPARATOR).append(stack.pop());
}
return buffer.toString();
}
@NotNull
public static String getLastUsedGradleHome() {
return PropertiesComponent.getInstance().getValue(LAST_USED_GRADLE_HOME_KEY, "");
}
public static void storeLastUsedGradleHome(@Nullable String gradleHomePath) {
if (gradleHomePath != null) {
PropertiesComponent.getInstance().setValue(LAST_USED_GRADLE_HOME_KEY, gradleHomePath);
}
}
}