/*******************************************************************************
* Copyright (c) 2015 Mentor Graphics 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:
* Mentor Graphics - initial API and implementation
*******************************************************************************/
package com.codesourcery.internal.installer;
import java.io.File;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.equinox.internal.p2.metadata.BasicVersion;
import org.eclipse.equinox.internal.p2.metadata.OSGiVersion;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.MetadataFactory;
import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import com.codesourcery.installer.Installer;
/**
* This class manages a temporary repository containing an installable unit (IU) for the product. The IU is set with
* requirements on the IU's corresponding to installation components and is used to provision the product.
*/
@SuppressWarnings("restriction") // P2 internal OSGiVersion used
public class ProductRepository {
/** Meta-data repository manager */
private IMetadataRepositoryManager metadataRepositoryManager;
/** Product meta-data repository */
private IMetadataRepository metadataRepository;
/** Repository directory */
private File repositoryDirectory;
/** Product IU */
private IInstallableUnit productIu;
/**
* Constructs a product repository.
*
* @param agent Provisioning agent
*/
public ProductRepository(IProvisioningAgent agent) {
metadataRepositoryManager = (IMetadataRepositoryManager)agent.getService(IMetadataRepositoryManager.SERVICE_NAME);
}
/**
* @return The meta-data repository manager.
*/
protected IMetadataRepositoryManager getMetadataRepositoryManager() {
return metadataRepositoryManager;
}
/**
* @return The product meta-data repository.
*/
protected IMetadataRepository getMetadataRepository() {
return metadataRepository;
}
/**
* @return The product name.
*/
protected String getProductName() {
return Installer.getDefault().getInstallManager().getInstallDescription().getProductName();
}
/**
* @return The product identifier.
*/
protected String getProductId() {
return Installer.getDefault().getInstallManager().getInstallDescription().getProductId();
}
/**
* @return The product version.
*/
protected Version getProductVersion() {
return Installer.getDefault().getInstallManager().getInstallDescription().getProductVersion();
}
/**
* @return Returns the product vendor.
*/
protected String getProductVendor() {
return Installer.getDefault().getInstallManager().getInstallDescription().getProductVendor();
}
/**
* Creates the product meta-data repository.
* Clients should call {@link #dispose()} when the repository is no longer needed.
*
* @throws CoreException on failure
* @see #dispose()
*/
public IMetadataRepository createRepository() throws CoreException {
try {
// Create temporary directory for product repository
repositoryDirectory = Files.createTempDirectory(null).toFile();
// Create the P2 repository for meta-data information
metadataRepository = getMetadataRepositoryManager().createRepository(repositoryDirectory.toURI(), getProductName(),
IMetadataRepositoryManager.TYPE_SIMPLE_REPOSITORY, null);
Installer.log("Created product repository at: " + repositoryDirectory.getAbsolutePath());
}
catch (Exception e) {
Installer.fail(e);
}
return metadataRepository;
}
/**
* Creates the product IU and adds it to the product repository. The product IU will be created with the same
* name and identifier as specified for the product in the installer description. The product IU version will be
* set to the major, minor, and service version for the product specified in the installer description, unless if
* already exists in the profile. In that case, the version of the product IU will be set to the version of the
* existing profile IU but with the qualifier segment incremented.
*
* @param units IU's to be installed
* @return Product IU in the first element and the existing installed product IU if available in the second element.
* @throws CoreException on failure
*/
public IInstallableUnit[] createProductIu(IProfile profile, List<IInstallableUnit> units) throws CoreException {
IInstallableUnit[] productUnits = new IInstallableUnit[2];
try {
// Check if there is an existing product IU installed in the profile
IInstallableUnit existingProductIu = getProductIu(profile);
// Remove old IU
if (productIu != null) {
ArrayList<IInstallableUnit> ius = new ArrayList<IInstallableUnit>();
ius.add(productIu);
getMetadataRepository().removeInstallableUnits(ius);
}
// Product IU properties
HashMap<String, String> properties = new HashMap<String, String>();
properties.put(IInstallableUnit.PROP_NAME, getProductName());
if (getProductVendor() != null) {
properties.put(IInstallableUnit.PROP_PROVIDER, getProductVendor());
}
Version productVersion = null;
// If updating the install, increment the qualifier part of the product IU version
if (Installer.getDefault().getInstallManager().getInstallMode().isUpdate() && (existingProductIu != null)) {
final Version existingProductVersion = existingProductIu.getVersion();
if (existingProductVersion instanceof BasicVersion) {
OSGiVersion version = (OSGiVersion)existingProductVersion;
String qualifierSpec = version.getQualifier();
int qualifier = ((qualifierSpec == null) || qualifierSpec.isEmpty()) ?
0 :
Integer.parseInt(version.getQualifier());
// Create new product IU version
productVersion = OSGiVersion.createOSGi(
version.getMajor(),
version.getMinor(),
version.getMicro(),
String.format("%06d", qualifier + 1));
}
}
// Else use all parts of the product version except for the qualifier. The qualifier will be used to update
// the product IU when the install is updated.
else {
if (getProductVersion() instanceof OSGiVersion) {
OSGiVersion version = (OSGiVersion)getProductVersion();
productVersion = OSGiVersion.createOSGi(version.getMajor(), version.getMinor(), version.getMicro());
}
}
// This shouldn't happen
if (productVersion == null) {
Installer.fail("Product version is not in OSGI format.");
}
// Create product IU description
InstallableUnitDescription productIuDesc = InstallUtils.createIuDescription(
getProductId(),
productVersion,
true,
properties);
// Add requirements for the units
InstallUtils.addInstallableUnitRequirements(productIuDesc, units, false);
// Remove previous product IU
if (productIu != null) {
ArrayList<IInstallableUnit> ius = new ArrayList<IInstallableUnit>();
ius.add(productIu);
getMetadataRepository().removeInstallableUnits(ius);
}
// Create and add product IU
ArrayList<IInstallableUnit> ius = new ArrayList<IInstallableUnit>();
productIu = MetadataFactory.createInstallableUnit(productIuDesc);
ius.add(productIu);
getMetadataRepository().addInstallableUnits(ius);
// New product IU
productUnits[0] = productIu;
// Existing product IU
productUnits[1] = existingProductIu;
}
catch (Exception e) {
Installer.fail(e);
}
return productUnits;
}
/**
* Returns an existing product IU if available.
*
* @param profile Profile
* @return Product IU or <code>null</code>
*/
public IInstallableUnit getProductIu(IProfile profile) {
ProfileAdapter adapter = new ProfileAdapter(profile);
return adapter.findUnit(getProductId());
}
/**
* Disposes of the product repository.
*/
public void dispose() {
getMetadataRepositoryManager().removeRepository(metadataRepository.getLocation());
try {
FileUtils.deleteDirectory(repositoryDirectory.toPath());
Installer.log("Deleted product repository at: " + repositoryDirectory.getAbsolutePath());
}
// Could not delete the temporary repository
catch (Exception e) {
Installer.log(e);;
}
}
}