blob: da4d699e6bcb46c8ead7793afddc2a4af5678b99 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 Red Hat Inc. 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:
* Neil Guzman - initial API and implementation
*******************************************************************************/
package org.eclipse.linuxtools.internal.rpm.createrepo;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.linuxtools.rpm.core.utils.BufferedProcessInputStream;
import org.eclipse.linuxtools.rpm.core.utils.Utils;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.FrameworkUtil;
/**
* This class will execute the actual createrepo command.
*/
public class Createrepo {
/*
* Default commands that every execution will have.
*/
private static final String[] DEFAULT_ARGUMENTS = {
CreaterepoPreferenceConstants.PREF_VERBOSE, CreaterepoPreferenceConstants.PREF_PROFILE};
/**
* Holds the command line switches.
*/
private List<String> commandSwitches;
/**
* Initialize the command switches to be "createrepo" and
* default command arguments.
*/
public Createrepo() {
commandSwitches = new ArrayList<>();
commandSwitches.add(ICreaterepoConstants.CREATEREPO_COMMAND);
for (String arg : DEFAULT_ARGUMENTS) {
commandSwitches.add(ICreaterepoConstants.DASH.concat(arg));
}
}
/**
* Execute a createrepo command with custom arguments. The target directory
* will always be the current project's content folder and will automatically be
* added before execution. A blank list will result in the default createrepo execution.
*
* @param os Direct execution stream to this.
* @param project The project.
* @param commands A list of command switches to execute with the createrepo command.
* @return The status of the execution.
* @throws CoreException Occurs when error trying to execute the command.
*/
public IStatus execute(final OutputStream os, CreaterepoProject project, List<String> commands) throws CoreException {
IStatus available = checkIfAvailable();
if (!available.isOK()) {
return available;
}
IStatus validVersion = isCorrectVersion();
if (!validVersion.isOK()) {
return validVersion;
}
commandSwitches.addAll(commands);
commandSwitches.add(project.getContentFolder().getLocation().toOSString());
/* Display what the execution looks like */
String commandString = ICreaterepoConstants.EMPTY_STRING;
for (String arg : commandSwitches) {
commandString = commandString.concat(arg + " "); //$NON-NLS-1$
}
commandString = commandString.concat("\n"); //$NON-NLS-1$
try {
os.write(commandString.getBytes());
return Utils.runCommand(os, project.getProject(), commandSwitches.toArray(new String[commandSwitches.size()]));
} catch (IOException e) {
IStatus status = new Status(
IStatus.ERROR,
FrameworkUtil.getBundle(CreaterepoProject.class).getSymbolicName(),
NLS.bind(Messages.Createrepo_errorExecuting, commandString), e);
throw new CoreException(status);
}
}
/**
* Check if the createrepo command is available in the system.
*
* @return The status of whether or not createrepo was found.
* @throws CoreException Occurs when createrepo is not found or executing the command failed.
*/
public static IStatus checkIfAvailable() throws CoreException {
try {
BufferedProcessInputStream bpis = Utils.runCommandToInputStream("which", ICreaterepoConstants.CREATEREPO_COMMAND); //$NON-NLS-1$
// error executing "which createrepo", most likely due to it not being found
if (bpis.getExitValue() == 1) {
return new Status(IStatus.ERROR,
FrameworkUtil.getBundle(CreaterepoProject.class).getSymbolicName(),
Messages.Createrepo_errorCommandNotFound, null);
}
return Status.OK_STATUS;
} catch (IOException e) {
IStatus status = new Status(
IStatus.WARNING,
FrameworkUtil.getBundle(CreaterepoProject.class).getSymbolicName(),
Messages.Createrepo_errorTryingToFindCommand, e);
throw new CoreException(status);
} catch (InterruptedException e) {
IStatus status = new Status(
IStatus.CANCEL,
FrameworkUtil.getBundle(CreaterepoProject.class).getSymbolicName(),
Messages.Createrepo_jobCancelled, e);
throw new CoreException(status);
}
}
/**
* Grab the version of the system's createrepo command and if it
* is >= 0.9.8 and also has a yum version >= 3.2.23, then program
* can continue on executing.
*
* 0.9.8 = latest development release
* requires: yum version >= 3.2.23
*
* @return True if version is supported, false otherwise.
* @throws CoreException Occurs when failure to get version number.
*/
public static IStatus isCorrectVersion() throws CoreException {
final String CREATEREPO_VALID_VERSION = "0.9.8"; //$NON-NLS-1$
final String YUM_VALID_VERSION = "3.2.23"; //$NON-NLS-1$
String createrepoVersion = ICreaterepoConstants.EMPTY_STRING;
String yumVersion = ICreaterepoConstants.EMPTY_STRING;
try {
String repoOutput = Utils.runCommandToString(ICreaterepoConstants.CREATEREPO_COMMAND, "--version").trim(); //$NON-NLS-1$
// createrepo --version output is like:
// createrepo x.x.x
String[] createrepoTemp = repoOutput.split(" "); //$NON-NLS-1$
if (createrepoTemp.length > 1) {
createrepoVersion = createrepoTemp[1];
}
boolean createrepoValid = isGreaterOrEqual(createrepoVersion.split("\\."), CREATEREPO_VALID_VERSION.split("\\.")); //$NON-NLS-1$ //$NON-NLS-2$
// exit return an error early if the version does not meet the requirements
if (!createrepoValid) {
return new Status(
IStatus.ERROR,
FrameworkUtil.getBundle(CreaterepoProject.class).getSymbolicName(),
NLS.bind(Messages.Createrepo_errorWrongVersionCreaterepo, new String[] {
CREATEREPO_VALID_VERSION, createrepoVersion}),
null);
}
String yumOutput = Utils.runCommandToString("yum", "--version").trim(); //$NON-NLS-1$ //$NON-NLS-2$
// yum --version output is like:
// x.x.x
// blah...
// blah...
String[] yumTemp = yumOutput.split("\n"); //$NON-NLS-1$
if (yumTemp.length > 0) {
yumVersion = yumTemp[0];
}
boolean yumValid = isGreaterOrEqual(yumVersion.split("\\."), YUM_VALID_VERSION.split("\\.")); //$NON-NLS-1$ //$NON-NLS-2$
if (yumValid) {
// return an OK status only if yum is valid version
return Status.OK_STATUS;
} else {
// return an error status otherwise stating the versions in the message
return new Status(
IStatus.ERROR,
FrameworkUtil.getBundle(CreaterepoProject.class).getSymbolicName(),
NLS.bind(Messages.Createrepo_errorWrongVersionYum, new String[] {
YUM_VALID_VERSION, yumVersion}), null);
}
} catch (IOException e) {
IStatus status = new Status(
IStatus.CANCEL,
FrameworkUtil.getBundle(CreaterepoProject.class).getSymbolicName(),
Messages.Createrepo_errorCancelled, e);
throw new CoreException(status);
} catch (ArrayIndexOutOfBoundsException e) {
IStatus status = new Status(
IStatus.ERROR,
FrameworkUtil.getBundle(CreaterepoProject.class).getSymbolicName(),
NLS.bind(Messages.Createrepo_errorPasingVersion, new String[] {createrepoVersion, yumVersion}), e);
throw new CoreException(status);
}
}
/**
* Go through the version and compare if the current version passed is
* greater or equal to the minimum version required. Assumes left-most
* value is higher priority than right-most.
*
* The minimum should always follow a x.x.x version format, the current can
* be x or x.x or x.x.x
*
* @param current Current version to check.
* @param minimum The minimum version to pass.
* @return True if the current version is higher or equal to the minimum version.
*/
private static boolean isGreaterOrEqual(String[] current, String[] minimum) {
if (current.length > 0) {
try {
int iCurrent = Integer.parseInt(current[0]);
int iMinimum = minimum.length == 0 ? 0 : Integer.parseInt(minimum[0]);
if (iCurrent > iMinimum || (current.length == 1 && iCurrent == iMinimum)) {
return true;
} else if (iCurrent == iMinimum && current.length > 1){
return isGreaterOrEqual(Arrays.copyOfRange(current, 1, current.length),
Arrays.copyOfRange(minimum, 1, minimum.length));
} else {
return false;
}
} catch (NumberFormatException e) {
return false;
}
}
return false;
}
}