blob: 007801d842311d46857ae7a42986ea063051575a [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.versioning.system.cvss.installer;
import java.awt.Dialog;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import org.netbeans.api.autoupdate.InstallSupport;
import org.netbeans.api.autoupdate.OperationContainer;
import org.netbeans.api.autoupdate.OperationException;
import org.netbeans.api.autoupdate.OperationSupport;
import org.netbeans.api.autoupdate.OperationSupport.Restarter;
import org.netbeans.api.autoupdate.UpdateElement;
import org.netbeans.api.autoupdate.UpdateManager;
import org.netbeans.api.autoupdate.UpdateUnit;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ui.OpenProjects;
import org.netbeans.modules.autoupdate.ui.api.PluginManager;
import org.netbeans.modules.versioning.spi.VersioningSupport;
import org.netbeans.modules.versioning.spi.VersioningSystem;
import org.netbeans.modules.versioning.system.cvss.installer.util.Utils;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.awt.Mnemonics;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.util.WeakListeners;
/**
*
* @author ondra
*/
@VersioningSystem.Registration(
displayName="#CTL_CvsInstaller_DisplayName",
menuLabel="",
actionsCategory="CVS",
metadataFolderNames="CVS")
public final class CvsInstaller extends VersioningSystem {
public static final Logger LOG = Logger.getLogger(CvsInstaller.class.getName());
private final Set<File> unversionedParents = Collections.synchronizedSet(new HashSet<File>(20));
public static final String FILENAME_CVS = "CVS"; //NOI18N
public static final String FILENAME_CVS_REPOSITORY = FILENAME_CVS + "/Repository"; // NOI18N
public static final String FILENAME_CVS_ENTRIES = FILENAME_CVS + "/Entries"; // NOI18N
private static final RequestProcessor RP = new RequestProcessor("CVS Installer", 1, false, false); //NOI18N
private final RequestProcessor.Task task;
private final AsyncTask installTask;
private static final String CVS_CODENAME = "org.netbeans.modules.versioning.system.cvss"; //NOI18N
private static final String INSTALLER_CODENAME = "org.netbeans.modules.versioning.system.cvss.installer"; //NOI18N
public CvsInstaller () {
installTask = new AsyncTask();
task = RP.create(installTask);
}
@Override
public File getTopmostManagedAncestor (File file) {
if (CvsInstallerModuleConfig.getInstance().isCvsInstalled()) {
// no need for this module, will be uninstalled
task.schedule(0);
return null;
}
if (CvsInstallerModuleConfig.getInstance().isIgnored()) {
return null;
}
return getTopmostManagedAncestor (file, false);
}
public File getTopmostManagedAncestor (File file, boolean internal) {
long t = System.currentTimeMillis();
LOG.log(Level.FINE, "getTopmostManagedParent {0}", new Object[] { file });
if(unversionedParents.contains(file)) {
LOG.fine(" cached as unversioned");
return null;
}
if (Utils.isPartOfCVSMetadata(file)) {
LOG.fine(" part of metaddata");
for (;file != null; file = file.getParentFile()) {
if (file.getName().equals(FILENAME_CVS) && (file.isDirectory() || !file.exists())) {
file = file.getParentFile();
LOG.log(Level.FINE, " will use parent {0}", new Object[] { file });
break;
}
}
}
Set<File> done = new HashSet<File>();
File topmost = null;
for (; file != null; file = file.getParentFile()) {
if(unversionedParents.contains(file)) {
LOG.log(Level.FINE, " already known as unversioned {0}", new Object[] { file });
break;
}
if (VersioningSupport.isExcluded(file)) break;
if (Utils.containsMetadata(file)) {
LOG.log(Level.FINE, " found managed parent {0}", new Object[] { file });
topmost = file;
done.clear(); // all folders added before must be removed, they ARE in fact managed by CVS
} else {
LOG.log(Level.FINE, " found unversioned {0}", new Object[] { file });
if(file.exists()) { // could be created later ...
done.add(file);
}
}
}
if(done.size() > 0) {
LOG.log(Level.FINE, " storing unversioned");
unversionedParents.addAll(done);
}
if(LOG.isLoggable(Level.FINE)) {
LOG.log(Level.FINE, " getTopmostManagedParent returns {0} after {1} millis", new Object[] { topmost, System.currentTimeMillis() - t });
}
if (internal) {
return topmost;
} else {
if (topmost != null) {
// now we have a cvs checkout and the download dialog has not been displayed or we're running with a fresh userdir
task.schedule(0);
}
return null;
}
}
private boolean isCvsInstalled () {
assert !EventQueue.isDispatchThread();
for (UpdateUnit u : UpdateManager.getDefault().getUpdateUnits()) {
if (CVS_CODENAME.equals(u.getCodeName())) {
return u.getInstalled() != null;
}
}
return false;
}
private static boolean downloadWindowDisplayed;
private class AsyncTask implements Runnable {
private PropertyChangeListener listener;
@Override
public void run () {
// cvs might have been installed manually, check that
if (CvsInstallerModuleConfig.getInstance().isCvsInstalled() || isCvsInstalled()) {
doFinish();
return;
}
if (downloadWindowDisplayed || CvsInstallerModuleConfig.getInstance().isIgnored()) {
return;
}
// cvs not yet installed, attach a listener to open projects and wait for a cvs project to be opened
OpenProjects projs = OpenProjects.getDefault();
if (listener == null) {
projs.addPropertyChangeListener(WeakListeners.propertyChange(listener = new PropertyChangeListener() {
@Override
public void propertyChange (PropertyChangeEvent evt) {
if (OpenProjects.PROPERTY_OPEN_PROJECTS.equals(evt.getPropertyName())) {
task.schedule(0);
}
}
}, projs));
}
Project[] projects;
try {
projects = projs.openProjects().get();
} catch (Exception ex) {
LOG.log(Level.INFO, null, ex);
projects = projs.getOpenProjects();
}
for (Project p : projects) {
FileObject fo = p.getProjectDirectory();
File f = FileUtil.toFile(fo);
// is the project directory under CVS control?
if (f != null && getTopmostManagedAncestor(f, true) != null) {
processCvsProject(p);
break;
}
}
}
private void doFinish () {
CvsInstallerModuleConfig.getInstance().setCvsInstalled(true);
if (listener != null) {
OpenProjects.getDefault().removePropertyChangeListener(listener);
listener = null;
}
assert !EventQueue.isDispatchThread();
for (UpdateUnit u : UpdateManager.getDefault().getUpdateUnits()) {
if (INSTALLER_CODENAME.equals(u.getCodeName()) && u.getInstalled() != null && !u.isPending()) {
OperationContainer<OperationSupport> container = OperationContainer.createForUninstall();
if (container.canBeAdded(u, u.getInstalled())) {
container.add(u, u.getInstalled());
try {
LOG.log(Level.INFO, "doFinish: uninstalling"); //NOI18N
OperationSupport support = container.getSupport();
Restarter restarter = support.doOperation(null);
LOG.log(Level.INFO, "doFinish: uninstalled"); //NOI18N
if (restarter != null) {
LOG.log(Level.INFO, "doFinish: restart scheduled"); //NOI18N
support.doRestartLater(restarter);
}
} catch (OperationException ex) {
LOG.log(Level.INFO, null, ex);
}
}
}
}
}
private void processCvsProject (Project p) {
JButton installButton = new JButton();
Mnemonics.setLocalizedText(installButton, NbBundle.getMessage(CvsInstallDialog.class, "CvsInstallDialog.downloadButton.text")); //NOI18N
CvsInstallDialog panel = new CvsInstallDialog();
DialogDescriptor dd = new DialogDescriptor(panel, NbBundle.getMessage(CvsInstallDialog.class, "CvsInstallDialog.title"), //NOI18N
true, new Object[] { installButton, DialogDescriptor.CANCEL_OPTION }, installButton, DialogDescriptor.DEFAULT_ALIGN, null, null);
Dialog dialog = DialogDisplayer.getDefault().createDialog(dd);
dialog.setVisible(true);
// no more dialog in the future
downloadWindowDisplayed = true;
if (listener != null) {
OpenProjects.getDefault().removePropertyChangeListener(listener);
listener = null;
}
// handle result
if (panel.cbDoNotAsk.isSelected()) {
CvsInstallerModuleConfig.getInstance().setIgnored(true);
}
if (dd.getValue() == installButton) {
// install CVS support
if (installCvsSupport()) {
// and uninstall me
doFinish();
} else {
// huh? probably a connection issue? user canceled the download or did not accept the license?
CvsInstallerModuleConfig.getInstance().setIgnored(false);
DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(NbBundle.getMessage(CvsInstaller.class, "CvsInstaller.installFailed"), //NOI18N
NotifyDescriptor.ERROR_MESSAGE));
}
}
}
private boolean installCvsSupport () {
assert !EventQueue.isDispatchThread();
for (UpdateUnit u : UpdateManager.getDefault().getUpdateUnits()) {
if (CVS_CODENAME.equals(u.getCodeName()) && u.getInstalled() == null) {
if (u.getAvailableUpdates().size() > 0) {
UpdateElement element = u.getAvailableUpdates().get(0);
OperationContainer<InstallSupport> container = OperationContainer.createForInstall();
if (container.canBeAdded(u, element)) {
container.add(u, element);
LOG.log(Level.INFO, "installCvsSupport: installing CVS"); //NOI18N
return PluginManager.openInstallWizard(container);
}
}
}
}
return false;
}
}
}