/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* Oracle and Java are registered trademarks of Oracle and/or its affiliates.
* Other names may be trademarks of their respective owners.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License. When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s):
*
* The Original Software is NetBeans. The Initial Developer of the Original
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
* Microsystems, Inc. All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*/
package org.netbeans.modules.ruby.railsprojects.plugins;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.ruby.platform.RubyPlatform;
import org.netbeans.modules.ruby.platform.execution.ExecutionUtils;
import org.netbeans.modules.ruby.platform.Util;
import org.netbeans.modules.ruby.railsprojects.RailsProject;
import org.netbeans.modules.ruby.platform.execution.RubyExecutionDescriptor;
import org.netbeans.modules.ruby.railsprojects.RailsProjectUtil;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.modules.InstalledFileLocator;
import org.openide.util.Exceptions;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
/**
* Class which handles plugin interactions - executing plugin, installing, uninstalling, etc.
*
* @todo Use the new ExecutionService to do process manapluginent.
* @todo Consolidate with the GemManager
*
* @author Tor Norbye
*/
public class PluginManager {
private static final String PLUGIN_CUSTOMIZER = "plugin.rb";
private RailsProject project;
/** Share over invocations of the dialog since these are slow to compute */
private List<Plugin> installed;
/** Share over invocations of the dialog since these are ESPECIALLY slow to compute */
private static List<Plugin> available;
private static List<Plugin> cachedAvailable;
public PluginManager(RailsProject project) {
this.project = project;
}
private FileObject getPluginDir() {
FileObject pluginDirPath = project.getProjectDirectory().getFileObject("vendor/plugins"); // NOI18N
return pluginDirPath;
}
/**
* Return null if there are no problems running plugin. Otherwise return
* an error message which describes the problem.
*/
public String getPluginProblem() {
FileObject pluginDirPath = getPluginDir();
if (pluginDirPath == null) {
// edge case, misconfiguration? plugin tool is installed but repository is not found
return NbBundle.getMessage(PluginAction.class, "CannotFindPluginRepository");
}
File pluginDir = FileUtil.toFile(pluginDirPath);
if (!pluginDir.canWrite()) {
return NbBundle.getMessage(PluginAction.class, "PluginNotWritable");
}
return null;
}
/**
* Checks whether a plugin with the given name is installed in the plugin
* repository used by the current Rails project
*
* @param pluginName name of a plugin to be checked
* @return <tt>true</tt> if installed; <tt>false</tt> otherwise
*/
public boolean isPluginInstalled(final String pluginName) {
FileObject dir = getPluginDir();
return dir != null && dir.getFileObject(pluginName) != null;
}
/** WARNING: slow call! Synchronous plugin execution (unless refresh==false)! */
public List<Plugin> getInstalledPlugins(boolean refresh, String sourceRepository, List<String> lines) {
if (refresh || (installed == null) || (installed.size() == 0)) {
installed = new ArrayList<Plugin>(40);
refreshList(installed, sourceRepository, true, lines);
}
return installed;
}
/** WARNING: slow call! Synchronous plugin execution! */
public List<Plugin> getAvailablePlugins(boolean refresh, String sourceRepository, List<String> lines) {
if (refresh || (available == null) || (available.size() == 0)) {
available = new ArrayList<Plugin>(300);
refreshList(available, sourceRepository, false, lines);
if (available.size() > 1) {
updateCachedList(lines);
}
}
return available;
}
public boolean hasUptodateAvailableList() {
// Turned off caching
//return available != null;
return false;
}
public List<Plugin> getCachedAvailablePlugins() {
// Turned off
if (true) {
return null;
}
if (available != null) {
return available;
}
if (cachedAvailable != null) {
return cachedAvailable;
}
cachedAvailable = getCachedList();
return cachedAvailable;
}
private void refreshList(final List<Plugin> list, String sourceRepository, final boolean local, final List<String> lines) {
list.clear();
// Install the given plugin
List<String> argList = new ArrayList<String>();
if (sourceRepository != null) {
argList.add("-s"); // NOI18N
argList.add(sourceRepository);
}
if (local) {
argList.add("--local"); // NOI18N
} else {
argList.add("--remote"); // NOI18N
}
String[] args = argList.toArray(new String[argList.size()]);
boolean ok = pluginRunner("list", null, null, lines, args); // NOI18N
if (ok) {
parsePluginList(lines, list, local);
// Sort the list
Collections.sort(list);
}
}
private void parsePluginList(List<String> lines, List<Plugin> pluginList, boolean local) {
Plugin plugin = null;
boolean listStarted = false;
for (String line : lines) {
// Pretty simple format - lines simply have the name on the left, and optionally
// a repository on the right.
// However, with the verbose flag there's more output. Even though I'm not
// using --verbose right now, prepare for it in case it's being picked up by
// user configuration files etc.
if (line.trim().length() == 0 || line.startsWith("/") || line.startsWith("Discovering plugins in ")) { // NOI18N
continue;
}
StringBuilder sb = new StringBuilder();
int i = 0;
int length = line.length();
for (; i < length; i++) {
char c = line.charAt(i);
if (Character.isWhitespace(c)) {
break;
}
sb.append(c);
}
String name = sb.toString();
for (; i < length; i++) {
if (Character.isWhitespace(line.charAt(i))) {
break;
}
}
// Skip whitespace
while (i < length && Character.isWhitespace(line.charAt(i))) {
i++;
}
String repository = null;
if (i < length) {
sb = new StringBuilder();
for (; i < length; i++) {
char c = line.charAt(i);
if (Character.isWhitespace(c)) {
break;
}
sb.append(c);
}
if (sb.length() > 0) {
repository = sb.toString();
}
}
plugin = new Plugin(name, repository);
pluginList.add(plugin);
}
}
/** Non-blocking plugin executor which also provides progress UI etc. */
private void asynchPluginRunner(final JComponent parent, final String description,
final String successMessage, final String failureMessage, final List<String> lines,
final Runnable successCompletionTask, final String command, final String... commandArgs) {
final Cursor originalCursor = parent.getCursor();
Cursor busy = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
parent.setCursor(busy);
final JButton closeButton = new JButton(NbBundle.getMessage(PluginManager.class, "CTL_Close"));
final JButton cancelButton =
new JButton(NbBundle.getMessage(PluginManager.class, "CTL_Cancel"));
closeButton.getAccessibleContext()
.setAccessibleDescription(NbBundle.getMessage(PluginManager.class, "AD_Close"));
Object[] options = new Object[] { closeButton, cancelButton };
closeButton.setEnabled(false);
final PluginProgressPanel progress =
new PluginProgressPanel(NbBundle.getMessage(PluginManager.class, "PluginPleaseWait"));
DialogDescriptor descriptor =
new DialogDescriptor(progress, description, true, options, closeButton,
DialogDescriptor.DEFAULT_ALIGN, new HelpCtx(PluginProgressPanel.class), null); // NOI18N
descriptor.setModal(true);
final Process[] processHolder = new Process[1];
final Dialog dlg = DialogDisplayer.getDefault().createDialog(descriptor);
closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
dlg.setVisible(false);
dlg.dispose();
parent.setCursor(originalCursor);
}
});
Runnable runner =
new Runnable() {
public void run() {
try {
boolean succeeded =
pluginRunner(command, progress, processHolder, lines, commandArgs);
closeButton.setEnabled(true);
cancelButton.setEnabled(false);
progress.done(succeeded ? successMessage : failureMessage);
if (succeeded && (successCompletionTask != null)) {
successCompletionTask.run();
}
} finally {
parent.setCursor(originalCursor);
}
}
};
RequestProcessor.getDefault().post(runner, 50);
dlg.setVisible(true);
if ((descriptor.getValue() == DialogDescriptor.CANCEL_OPTION) ||
(descriptor.getValue() == cancelButton)) {
parent.setCursor(originalCursor);
cancelButton.setEnabled(false);
Process process = processHolder[0];
if (process != null) {
process.destroy();
dlg.setVisible(false);
dlg.dispose();
}
}
}
private List<String> getPluginCmd() {
// XXX: basically just placeholder code as the plugin manager
// is disabled for Rails 3 projects as in Rails 3 it is not
// possible to list installed/available plugins, rendering
// the plugin manager basically useless
List<String> pluginCmd = new ArrayList<String>(2);
if (RailsProjectUtil.getRailsVersion(project).isRails3OrHigher()) {
pluginCmd.add("script" + File.separator + "rails");//NOI18N
pluginCmd.add("plugin"); //NOI18N
} else {
pluginCmd.add("script" + File.separator + "plugin"); // NOI18N
}
return pluginCmd;
}
private boolean pluginRunner(String command, PluginProgressPanel progressPanel,
Process[] processHolder, List<String> lines, String... commandArgs) {
List<String> argList = new ArrayList<String>();
RubyPlatform platform = RubyPlatform.platformFor(project);
File cmd = new File(platform.getInterpreter());
if (!cmd.getName().startsWith("jruby") || ExecutionUtils.launchJRubyScript()) { // NOI18N
argList.add(cmd.getPath());
}
argList.addAll(ExecutionUtils.getRubyArgs(platform));
// see #142698
argList.add("-r" + getPluginCustomizer().getAbsolutePath()); //NOI18N
argList.addAll(getPluginCmd());
argList.add(command);
for (String arg : commandArgs) {
argList.add(arg);
}
String[] args = argList.toArray(new String[argList.size()]);
ProcessBuilder pb = new ProcessBuilder(args);
File pwd = FileUtil.toFile(project.getProjectDirectory());
pb.directory(pwd);
pb.redirectErrorStream(true);
Util.adjustProxy(pb);
// PATH additions for JRuby etc.
RubyExecutionDescriptor descriptor = new RubyExecutionDescriptor(platform, "plugin", pb.directory()).cmd(cmd);
ExecutionUtils.setupProcessEnvironment(pb.environment(), descriptor.getCmd().getParent(), descriptor.getAppendJdkToPath());
if (lines == null) {
lines = new ArrayList<String>(40);
}
int exitCode = -1;
try {
Process process = pb.start();
if (processHolder != null) {
processHolder[0] = process;
}
InputStream is = process.getInputStream();
if (progressPanel != null) {
progressPanel.setProcessInput(process.getOutputStream());
}
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
try {
while (true) {
line = br.readLine();
if (line == null) {
break;
}
if (progressPanel != null) {
// Add "\n" ?
progressPanel.appendOutput(line);
}
lines.add(line);
}
} catch (IOException ioe) {
// When we cancel we call Process.destroy which may quite possibly
// raise an IO Exception in this thread reading text out of the
// process. Silently ignore that.
String message = "*** Plugin Process Killed ***\n"; // NOI18N
lines.add(message);
if (progressPanel != null) {
progressPanel.appendOutput(message);
}
}
exitCode = process.waitFor();
if (exitCode != 0) {
try {
// This might not be necessary now that I'm
// calling ProcessBuilder.redirectErrorStream(true)
// but better safe than sorry
is = process.getErrorStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
if (progressPanel != null) {
// Add "\n" ?
progressPanel.appendOutput(line);
}
lines.add(line);
}
} catch (IOException ioe) {
// When we cancel we call Process.destroy which may quite possibly
// raise an IO Exception in this thread reading text out of the
// process. Silently ignore that.
String message = "*** Plugin Process Killed ***\n"; // NOI18N
lines.add(message);
if (progressPanel != null) {
progressPanel.appendOutput(message);
}
}
}
} catch (IOException ex) {
ErrorManager.getDefault().notify(ex);
} catch (InterruptedException ex) {
ErrorManager.getDefault().notify(ex);
}
boolean succeeded = exitCode == 0;
// see #142698
if (succeeded && "remove".equals(command) && commandArgs != null && commandArgs[0] != null) { //NOI18N
FileObject plugin = project.getProjectDirectory().getFileObject("vendor/plugins/" + commandArgs[0]); //NOI18N
if (plugin != null) {
try {
plugin.delete();
} catch (IOException ex) {
succeeded = false;
Exceptions.printStackTrace(ex);
}
}
}
return succeeded;
}
/**
* Install the given plugin.
*
* @param plugin Plugin description for the plugin to be installed. Only the name is relevant.
* @param parent For asynchronous tasks, provide a parent JComponent that will have progress dialogs added,
* a possible cursor change, etc.
* @param asynchronous If true, run the plugin task asynchronously - returning immediately and running the plugin task
* in a background thread. A progress bar and message will be displayed (along with the option to view the
* plugin output). If the exit code is normal, the completion task will be run at the end.
* @param asyncCompletionTask If asynchronous is true and the plugin task completes normally, this task will be run at the end.
* @param rdoc If true, generate rdoc as part of the installation
* @param ri If true, generate ri data as part of the installation
* @param version If non null, install the specified version rather than the latest available version
*/
public boolean install(Plugin[] plugins, JComponent parent, String sourceRepository,
boolean svnExternals, boolean svnCheckout, String revision, boolean asynchronous,
Runnable asyncCompletionTask) {
// Install the given plugin
List<String> argList = new ArrayList<String>();
if (sourceRepository != null) {
argList.add("-s"); // NOI18N
argList.add(sourceRepository);
}
//argList.add("--verbose"); // NOI18N
for (Plugin plugin : plugins) {
argList.add(plugin.getName());
}
if (svnExternals) {
argList.add("--externals"); // NOI18N
} else if (svnCheckout) {
argList.add("--checkout"); // NOI18N
}
if (revision != null && (svnExternals || svnCheckout)) {
argList.add("--revision"); // NOI18N
argList.add(revision);
}
// see #123758
argList.add("--force"); //NOI18N
String[] args = argList.toArray(new String[argList.size()]);
String title = NbBundle.getMessage(PluginManager.class, "Installation");
String success = NbBundle.getMessage(PluginManager.class, "InstallationOk");
String failure = NbBundle.getMessage(PluginManager.class, "InstallationFailed");
String pluginCmd = "install"; // NOI18N
if (asynchronous) {
asynchPluginRunner(parent, title, success, failure, null, asyncCompletionTask, pluginCmd, args);
return false;
} else {
boolean ok = pluginRunner(pluginCmd, null, null, null, args);
return ok;
}
}
/**
* Uninstall the given plugin.
*
* @param plugin Plugin description for the plugin to be uninstalled. Only the name is relevant.
* @param parent For asynchronous tasks, provide a parent JComponent that will have progress dialogs added,
* a possible cursor change, etc.
* @param asynchronous If true, run the plugin task asynchronously - returning immediately and running the plugin task
* in a background thread. A progress bar and message will be displayed (along with the option to view the
* plugin output). If the exit code is normal, the completion task will be run at the end.
* @param asyncCompletionTask If asynchronous is true and the plugin task completes normally, this task will be run at the end.
*/
public boolean uninstall(Plugin[] plugins, String sourceRepository, JComponent parent,
boolean asynchronous, Runnable asyncCompletionTask) {
// Install the given plugin
List<String> argList = new ArrayList<String>();
if (sourceRepository != null) {
argList.add("-s"); // NOI18N
argList.add(sourceRepository);
}
// This string is replaced in the loop below, one gem at a time as we iterate over the
// deletion results
int nameIndex = argList.size();
argList.add("placeholder"); // NOI18N
//argList.add("--verbose"); // NOI18N
String[] args = argList.toArray(new String[argList.size()]);
String title = NbBundle.getMessage(PluginManager.class, "Uninstallation");
String success = NbBundle.getMessage(PluginManager.class, "UninstallationOk");
String failure = NbBundle.getMessage(PluginManager.class, "UninstallationFailed");
String pluginCmd = "remove"; // NOI18N
if (asynchronous) {
for (Plugin plugin : plugins) {
args[nameIndex] = plugin.getName();
asynchPluginRunner(parent, title, success, failure, null, asyncCompletionTask, pluginCmd,
args);
}
return false;
} else {
boolean ok = true;
for (Plugin plugin : plugins) {
args[nameIndex] = plugin.getName();
if (!pluginRunner(pluginCmd, null, null, null, args)) {
ok = false;
}
}
return ok;
}
}
/**
* Update the given plugin, or all plugins if plugin == null
*
* @param plugin Plugin description for the plugin to be uninstalled. Only the name is relevant. If null, all installed plugins
* will be updated.
* @param parent For asynchronous tasks, provide a parent JComponent that will have progress dialogs added,
* a possible cursor change, etc.
* @param asynchronous If true, run the plugin task asynchronously - returning immediately and running the plugin task
* in a background thread. A progress bar and message will be displayed (along with the option to view the
* plugin output). If the exit code is normal, the completion task will be run at the end.
* @param asyncCompletionTask If asynchronous is true and the plugin task completes normally, this task will be run at the end.
*/
public boolean update(Plugin[] plugins, String revision, String sourceRepository, JComponent parent,
boolean asynchronous, Runnable asyncCompletionTask) {
// Install the given plugin
List<String> argList = new ArrayList<String>();
if (sourceRepository != null) {
argList.add("-s"); // NOI18N
argList.add(sourceRepository);
}
//argList.add("--verbose"); // NOI18N
// If you specify a revision, only specify a single plugin
assert revision == null || revision.length() == 0 || plugins.length == 1;
if (plugins != null) {
for (Plugin plugin : plugins) {
argList.add(plugin.getName());
}
}
if (revision != null) {
argList.add("--revision"); // NOI18N
argList.add(revision);
}
String[] args = argList.toArray(new String[argList.size()]);
String title = NbBundle.getMessage(PluginManager.class, "Update");
String success = NbBundle.getMessage(PluginManager.class, "UpdateOk");
String failure = NbBundle.getMessage(PluginManager.class, "UpdateFailed");
String pluginCmd = "update"; // NOI18N
if (asynchronous) {
asynchPluginRunner(parent, title, success, failure, null, asyncCompletionTask, pluginCmd, args);
return false;
} else {
boolean ok = pluginRunner(pluginCmd, null, null, null, args);
return ok;
}
}
public boolean removeRepositories(String[] repositories, JComponent parent, ProgressHandle progressHandle,
boolean asynchronous, Runnable asyncCompletionTask) {
return modifyRepositories("unsource", repositories, parent, progressHandle, asynchronous, asyncCompletionTask); // NOI18N
}
public boolean addRepositories(String[] repositories, JComponent parent, ProgressHandle progressHandle,
boolean asynchronous, Runnable asyncCompletionTask) {
return modifyRepositories("source", repositories, parent, progressHandle, asynchronous, asyncCompletionTask); // NOI18N
}
public boolean modifyRepositories(String pluginCmd, String[] repositories, JComponent parent, ProgressHandle progressHandle,
boolean asynchronous, Runnable asyncCompletionTask) {
// Install the given plugin
List<String> argList = new ArrayList<String>();
//argList.add("--verbose"); // NOI18N
// If you specify a revision, only specify a single plugin
for (String repository : repositories) {
argList.add(repository);
}
String[] args = argList.toArray(new String[argList.size()]);
String title = NbBundle.getMessage(PluginManager.class, "ModifySource");
String success = NbBundle.getMessage(PluginManager.class, "ModifySourceOk");
String failure = NbBundle.getMessage(PluginManager.class, "ModifySourceFailed");
if (asynchronous) {
asynchPluginRunner(parent, title, success, failure, null, asyncCompletionTask, pluginCmd, args);
return false;
} else {
boolean ok = pluginRunner(pluginCmd, null, null, null, args);
return ok;
}
}
public List<String> getRepositories(boolean local) {
return local ? getLocalRepositories() : getRemoteRepositories();
}
private List<String> getRemoteRepositories() {
List<String> lines = new ArrayList<String>(150);
// Install the given plugin
List<String> argList = new ArrayList<String>();
argList.add("--list"); // NOI18N
String[] args = argList.toArray(new String[argList.size()]);
boolean ok = pluginRunner("discover", null, null, lines, args); // NOI18N
if (ok) {
return lines;
} else {
return Collections.emptyList();
}
}
private List<String> getLocalRepositories() {
List<String> lines = new ArrayList<String>(150);
// Install the given plugin
List<String> argList = new ArrayList<String>();
//argList.add("--check"); // NOI18N
String[] args = argList.toArray(new String[argList.size()]);
boolean ok = pluginRunner("sources", null, null, lines, args); // NOI18N
if (ok) {
return lines;
} else {
return Collections.emptyList();
}
}
private List<Plugin> getCachedList() {
synchronized (PluginManager.class) {
BufferedReader is = null;
try {
File cacheFile = getCacheFile();
if (!cacheFile.exists()) {
return null;
}
List<String> lines = new ArrayList<String>(5000);
is = new BufferedReader(new FileReader(getCacheFile()));
while (true) {
String line = is.readLine();
if (line == null) {
break;
}
lines.add(line);
}
List<Plugin> list = new ArrayList<Plugin>();
parsePluginList(lines, list, false);
return list;
} catch (IOException ioe) {
Exceptions.printStackTrace(ioe);
return null;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ioe) {
Exceptions.printStackTrace(ioe);
}
}
}
}
}
private void updateCachedList(List<String> lines) {
// Disabled for now
if (true) {
return;
}
synchronized (PluginManager.class) {
PrintWriter os = null;
try {
File cacheFile = getCacheFile();
if (cacheFile.exists()) {
cacheFile.delete();
}
os = new PrintWriter(new BufferedWriter(new FileWriter(getCacheFile())));
for (String line : lines) {
os.println(line);
}
} catch (IOException ioe) {
Exceptions.printStackTrace(ioe);
} finally {
if (os != null) {
os.close();
}
}
}
}
private static File getCacheFile() {
return new File(getCacheFolder(), "remotePlugins.txt"); // NOI18N
}
private static File getCacheFolder() {
final String nbUserProp = System.getProperty("netbeans.user"); // NOI18N
assert nbUserProp != null;
final File nbUserDir = new File(nbUserProp);
File cacheFolder =
FileUtil.normalizeFile(new File(nbUserDir,
"var" + File.separator + "cache" + File.separatorChar)); // NOI18N
if (!cacheFolder.exists()) {
boolean created = cacheFolder.mkdirs();
assert created : "Cannot create cache folder"; //NOI18N
} else {
assert cacheFolder.isDirectory() && cacheFolder.canRead() && cacheFolder.canWrite();
}
return cacheFolder;
}
private static synchronized File getPluginCustomizer() {
File pluginScript = InstalledFileLocator.getDefault().locate(
PLUGIN_CUSTOMIZER, "org.netbeans.modules.ruby.railsproject", false); // NOI18N
if (pluginScript == null) {
throw new IllegalStateException("Could not locate " + PLUGIN_CUSTOMIZER); // NOI18N
}
return pluginScript;
}
}