/*******************************************************************************
* Copyright (c) 2007, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Code 9 - ongoing development
* Mentor Graphics - Modified from original P2 stand-alone installer
*******************************************************************************/
package com.codesourcery.internal.installer;
import java.io.File;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.swt.widgets.Display;
import com.codesourcery.installer.IInstallDescription;
import com.codesourcery.installer.IInstallMode.InstallerRunMode;
import com.codesourcery.installer.Installer;
import com.codesourcery.internal.installer.ui.GUIInstallOperation;
/**
* This is an installer application build using P2. The application must be
* provided an "install description" for installation or "install manifest" for
* uninstallation.
*/
public class InstallApplication implements IApplication {
/**
* Creates the install operation.
*
* @return Install operation
*/
private InstallOperation createInstallOperation() {
InstallOperation operation = null;
InstallerRunMode runMode;
// Silent installation
if (Installer.getDefault().hasCommandLineOption(IInstallConstants.COMMAND_LINE_INSTALL_SILENT)) {
runMode = InstallerRunMode.SILENT;
operation = createSilentInstallOperation();
}
// Console installation
else if (Installer.getDefault().hasCommandLineOption(IInstallConstants.COMMAND_LINE_INSTALL_CONSOLE)) {
runMode = InstallerRunMode.CONSOLE;
operation = createConsoleInstallOperation();
}
// Wizard based UI installation
else {
runMode = InstallerRunMode.GUI;
operation = createGuiInstallOperation();
// If no display is available, use console install
if (operation == null) {
operation = createConsoleInstallOperation();
}
}
// Set install mode
if (Installer.getDefault().getInstallManager() != null) {
InstallMode installMode = (InstallMode)Installer.getDefault().getInstallManager().getInstallMode();
installMode.setRunMode(runMode);
}
// Status file option
if (Installer.getDefault().hasCommandLineOption(IInstallConstants.COMMAND_LINE_STATUS)) {
String statusFile = Installer.getDefault().getCommandLineOption(IInstallConstants.COMMAND_LINE_STATUS);
operation.setStatusFile(InstallUtils.resolvePath(statusFile));
}
return operation;
}
/**
* Creates a console install operation.
*
* @return Console install operation
*/
private InstallOperation createConsoleInstallOperation() {
ConsoleInstallOperation consoleOperation = new ConsoleInstallOperation();
try {
// Set maximum number of lines to display
String consoleArg = Installer.getDefault().getCommandLineOption(IInstallConstants.COMMAND_LINE_INSTALL_CONSOLE);
if (consoleArg != null) {
consoleOperation.setMaxLines(Integer.parseInt(consoleArg));
}
}
catch (NumberFormatException e) {
consoleOperation.showError(InstallMessages.Error_InvalidNumberOfLines);
}
return consoleOperation;
}
/**
* Creates a silent install operation.
*
* @return Silent install operation
*/
private InstallOperation createSilentInstallOperation() {
return new SilentInstallOperation();
}
/**
* Creates a GUI install operation.
*
* @return GUI install operation or <code>null</code> if no display is
* available
*/
private InstallOperation createGuiInstallOperation() {
GUIInstallOperation guiInstallOperation = null;
Display display = Display.getCurrent();
if (display == null) {
try {
display = new Display();
}
catch (Throwable e) {
// Ignore - no display available
}
}
if (display != null) {
guiInstallOperation = new GUIInstallOperation();
}
return guiInstallOperation;
}
@Override
public Object start(IApplicationContext appContext) {
// Run once then delete installer
File selfDirectory = null;
boolean runOnce = Installer.getDefault().hasCommandLineOption(IInstallConstants.COMMAND_LINE_INSTALL_ONCE);
if (runOnce) {
try {
selfDirectory = Installer.getDefault().getInstallFile("");
ShutdownHandler.getDefault().addDirectoryToRemove(selfDirectory.getAbsolutePath(), false);
String tempDir = System.getenv(IInstallConstants.P2_INSTALLER_TEMP_PATH);
if (tempDir == null) {
tempDir = System.getProperty("java.io.tmpdir");
}
if (tempDir != null) {
removeParentDirectories(selfDirectory, tempDir);
}
}
catch (Exception e) {
Installer.log(e);
}
}
// Print usage and exit
if (Installer.getDefault().hasCommandLineOption(IInstallConstants.COMMAND_LINE_INSTALL_HELP)) {
printUsage();
// Due to a bug, an exception will be thrown if an RCP
// application exits before the Gogo shell is initialized.
// Wait for shell to initialize before exiting.
// See: https://issues.apache.org/jira/browse/FELIX-3354
try { Thread.sleep(1000); } catch (InterruptedException e) {}
return IApplication.EXIT_OK;
}
// Set application running
appContext.applicationRunning();
initializeNetworkSettings();
initializeProxySupport();
// Create install operation
InstallOperation installOperation = createInstallOperation();
if (installOperation == null) {
Installer.logError(InstallMessages.Error_InstallOperation);
}
// Another instance is already running
if (!Installer.getDefault().hasLock()) {
installOperation.showError(InstallMessages.Error_AlreadyRunning);
}
// Run install operation
else {
installOperation.run();
}
// If run once and an unlocked repos directory is present, delete it before shutting down as it may contain
// P2 repository files larger than instmon can handle currently (> 2GB).
if (runOnce && (selfDirectory != null)) {
try {
File reposDirectory = new File(selfDirectory, "repos");
if (reposDirectory.exists()) {
FileUtils.deleteDirectory(reposDirectory.toPath());
}
}
catch (Exception e) {
Installer.log(e);
}
}
return IApplication.EXIT_OK;
}
/**
* Remove any parent directories in the temporary path above the installer. This is to
* remove any temporary directories created by SFX. Note the installerDir itself will
* be removed before any parent directories are removed. Furthermore, none of the additional
* parent directories will be removed if they are not already empty. If the temp directory
* is not a prefix of the installer directory, no parent directories are removed.
*
* @param installerDirectory - Directory containing the installer
* @param tempDir - Temp directory used to extract installer
*/
private void removeParentDirectories(File installerDirectory,
String tempDir) {
IPath tempDirPath = new Path(tempDir);
IPath installDirPath = new Path(installerDirectory.getAbsolutePath());
if (tempDirPath.isPrefixOf(installDirPath)) {
// The following segment was already removed by the calling method
installDirPath = installDirPath.removeLastSegments(1);
File tempDirFile = tempDirPath.toFile();
while (!installDirPath.toFile().equals(tempDirFile)) {
ShutdownHandler.getDefault().addDirectoryToRemove(installDirPath.toOSString(), true);
installDirPath = installDirPath.removeLastSegments(1);
}
}
else {
Installer.log("Parent temp directory for installer not removed because \"" + tempDirPath.toOSString() + "\" is not a prefix of \"" + installDirPath.toOSString() + "\".");
}
}
/**
* Initializes proxy support
*/
private void initializeProxySupport() {
// Note: Proxies are not currently supported. If this functionality
// is required, see the original P2 stand-alone installer.
}
/**
* Initialize network settings.
*/
private void initializeNetworkSettings() {
try {
IInstallDescription desc = Installer.getDefault().getInstallManager().getInstallDescription();
if (desc != null) {
int timeout = desc.getNetworkTimeout();
if (timeout != -1) {
String timeoutValue = Integer.toString(timeout);
System.setProperty("org.eclipse.ecf.provider.filetransfer.retrieve.connectTimeout", timeoutValue);
System.setProperty("org.eclipse.ecf.provider.filetransfer.retrieve.closeTimeout", timeoutValue);
System.setProperty("org.eclipse.ecf.provider.filetransfer.retrieve.readTimeout", timeoutValue);
System.setProperty("org.eclipse.ecf.provider.filetransfer.httpclient.browse.connectTimeout", timeoutValue);
System.setProperty("org.eclipse.ecf.provider.filetransfer.httpclient.retrieve.connectTimeout", timeoutValue);
System.setProperty("org.eclipse.ecf.provider.filetransfer.httpclient.retrieve.connectTimeout", timeoutValue);
System.setProperty("org.eclipse.ecf.provider.filetransfer.httpclient.retrieve.readTimeout", timeoutValue);
}
int retry = desc.getNetworkRetry();
if (retry != -1) {
String retryValue = Integer.toString(retry);
System.setProperty("org.eclipse.ecf.provider.filetransfer.retrieve.retryAttempts", retryValue);
System.setProperty("org.eclipse.equinox.p2.transport.ecf.retry", retryValue);
}
}
}
catch (Exception e) {
Installer.log(e);
}
}
/* (non-Javadoc)
* @see org.eclipse.equinox.app.IApplication#stop()
*/
public void stop() {
}
/**
* Prints usage
*/
private void printUsage() {
System.out.println(InstallMessages.Help_Usage);
printHelp(IInstallConstants.COMMAND_LINE_INSTALL_HELP, InstallMessages.Help_Help);
printHelp(IInstallConstants.COMMAND_LINE_INSTALL_LOCATION + "=\"<location>\"", InstallMessages.Help_InstallLocation);
printHelp(IInstallConstants.COMMAND_LINE_INSTALL_DESCRIPTION + "=\"<install.properties>\"", InstallMessages.Help_InstallDescription);
printHelp(IInstallConstants.COMMAND_LINE_INSTALL_MANIFEST + "=\"<install.manifest>\"", InstallMessages.Help_InstallManifest);
printHelp(IInstallConstants.COMMAND_LINE_INSTALL_CONSOLE, InstallMessages.Help_Console);
printHelp(IInstallConstants.COMMAND_LINE_INSTALL_SILENT, InstallMessages.Help_Silent);
printHelp("-nosplash", InstallMessages.Help_NoSplash);
printHelp(IInstallConstants.COMMAND_LINE_INSTALL_ONCE, InstallMessages.Help_InstallOnce);
printHelp(IInstallConstants.COMMAND_LINE_INSTALL_PROPERTY + "<property>=\"<value>\"", InstallMessages.Help_Property);
printHelp(IInstallConstants.COMMAND_LINE_STATUS + "=\"<status file path>\"", InstallMessages.Help_Status);
}
/**
* Prints formatted help for a command.
*
* @param command Command
* @param description Command description
*/
private void printHelp(String command, String description) {
StringBuffer buffer = new StringBuffer();
buffer.append(command);
for (int i = 0; i < 40 - command.length(); i ++) {
buffer.append(' ');
}
buffer.append(description);
System.out.println(buffer.toString());
}
}