/*******************************************************************************
* Copyright (c) 2015 ARM Ltd. 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:
* ARM Ltd and ARM Germany GmbH - Initial API and implementation
*******************************************************************************/
package com.arm.cmsis.pack.data;
import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.arm.cmsis.pack.CpPlugIn;
import com.arm.cmsis.pack.common.CmsisConstants;
import com.arm.cmsis.pack.generic.IAttributes;
import com.arm.cmsis.pack.utils.VersionComparator;
/**
* Default implementation of ICpPack interface
*/
public class CpPack extends CpRootItem implements ICpPack {
protected String version = null;
protected PackState state = PackState.UNKNOWN;
protected Map<String, ICpItem> conditions = null; // sorted map for quick access to conditions
protected Set<String> deviceNames = null; // names of all declared and referenced devices
protected Set<String> boardNames = null; // names of boards described in the pack
protected int deviceLess = -1; // -1 means uninitialized
protected int deprecated = -1; // -1 means uninitialized
public CpPack() {
this(NULL_CPITEM);
}
public CpPack(ICpItem parent) {
this(parent, CmsisConstants.PACKAGE_TAG);
}
public CpPack(ICpItem parent, String tag) {
super(parent, tag);
}
public CpPack(String tag, String fileName) {
super(tag, fileName);
}
@Override
public ICpPack getPack() {
return this;
}
@Override
public ICpItem createItem(ICpItem parent, String tag) {
// in all other cases call super class
return super.createItem(parent, tag);
}
@Override
public PackState getPackState() {
return state;
}
@Override
public void setPackState(PackState state) {
this.state = state;
}
@Override
public boolean isGenerated() {
return state == PackState.GENERATED;
}
@Override
public synchronized ICpItem getCondition(String conditionId) {
if(conditionId == null || conditionId.isEmpty()) {
return null;
}
if(conditions == null) {
// fill conditions map for quick access
conditions = new HashMap<String, ICpItem>();
ICpItem conditionsItem = getFirstChild(CmsisConstants.CONDITIONS_TAG);
if(conditionsItem != null) {
Collection<? extends ICpItem> items = conditionsItem.getChildren();
for(ICpItem c : items) {
conditions.put(c.getId(), c);
}
}
}
return conditions.get(conditionId);
}
@Override
public synchronized ICpGenerator getGenerator(String id) {
Collection<? extends ICpItem> generators = getGrandChildren(CmsisConstants.GENERATORS_TAG);
if(generators != null) {
for(ICpItem g : generators) {
if(!(g instanceof ICpGenerator)) {
continue;
}
if(id == null || id.isEmpty() || g.getId().equals(id) ) {
return (ICpGenerator)g;
}
}
}
return null;
}
@Override
public synchronized String getInstallDir(final String packRoot) {
if(packRoot == null || getPackState() == PackState.GENERATED) {
// installed and generator files are already located at their installation directories
return getRootDir(true);
}
// construct installation path out of Pack properties, use forward slashes
String dir = packRoot;
dir += '/' + getVendor() + '/' + getName() + '/' + getVersion() + '/';
return dir;
}
@Override
public String getName() {
ICpItem nameItem = getFirstChild(CmsisConstants.NAME);
if(nameItem != null) {
return nameItem.getText();
}
return CmsisConstants.EMPTY_STRING;
}
@Override
public String getVendor() {
ICpItem vendorItem = getFirstChild(CmsisConstants.VENDOR);
if(vendorItem != null) {
return vendorItem.getText();
}
return CmsisConstants.EMPTY_STRING;
}
@Override
public synchronized String getVersion() {
if( version == null) {
ICpItem releases = getFirstChild(CmsisConstants.RELEASES_TAG);
if(releases != null && releases.hasChildren()) {
for(ICpItem r : releases.getChildren()){
String v = r.getAttribute(CmsisConstants.VERSION);
if( VersionComparator.versionCompare(v, version) > 0) {
version = v;
}
}
}
if( version == null) {
version = CmsisConstants.EMPTY_STRING;
}
}
return version;
}
@Override
public synchronized String getUrl() {
if(fURL == null) {
ICpItem urlItem = getFirstChild(CmsisConstants.URL);
if(urlItem != null) {
fURL = urlItem.getText();
} else {
fURL = CmsisConstants.EMPTY_STRING;
}
}
return fURL;
}
@Override
public String constructId() {
// construct Pack ID in the form "Vendor.Name.Version"
return getPackFamilyId() + '.' + getVersion();
}
@Override
public String getPackFamilyId() {
return getVendor() + '.' + getName();
}
/**
* Extracts version from id string
* @param id Pack ID string
* @return version string if found, null otherwise
*/
public static String versionFromId(final String id){
if(id == null) {
return CmsisConstants.EMPTY_STRING;
}
int pos = id.indexOf('.'); // find first separator
if(pos > 0 ) {
pos = id.indexOf('.', pos+1); // find second separator
if(pos > 0 )
{
return id.substring(pos+1); // the rest is version (is any)
}
}
return CmsisConstants.EMPTY_STRING;
}
/**
* Returns Pack family ID : pack ID without version, i.e. the form Vendor.Name
* @param id Pack ID string
* @return family pack ID
*/
public static String familyFromId(final String id){
if(id == null) {
return CmsisConstants.EMPTY_STRING;
}
int pos = id.indexOf('.'); // find first separator
if(pos > 0 ) {
pos = id.indexOf('.', pos+1); // find second separator
if(pos > 0 )
{
return id.substring(0, pos); // extract prefix (strip version)
}
}
return id; // id has already no version
}
public static String constructPackId(IAttributes packAttributes) {
String vendor = packAttributes.getAttribute(CmsisConstants.VENDOR);
String name = packAttributes.getAttribute(CmsisConstants.NAME);
String version = packAttributes.getAttribute(CmsisConstants.VERSION);
String packId = vendor + '.' + name;
if (CmsisConstants.FIXED.equals(packAttributes.getAttribute(CmsisConstants.VERSION_MODE))) { // use fixed version of the pack
packId += '.' + version;
} else { // use latest compatible version of the pack
ICpPackCollection allPacks = CpPlugIn.getPackManager().getPacks();
if (allPacks == null) {
return CmsisConstants.EMPTY_STRING;
}
String familyId = CpPack.familyFromId(packId);
Collection<? extends ICpItem> packs = allPacks.getPacksByPackFamilyId(familyId);
if (packs == null) {
return CmsisConstants.EMPTY_STRING;
}
ICpItem latestPack = packs.iterator().next();
String latestVersion = latestPack.getVersion();
int verCmp = VersionComparator.versionCompare(latestVersion, version);
if (isPackFamilyId(packId) && verCmp >= 0 && verCmp < 4) { // compatible
packId += '.' + latestVersion;
} else {
packId += '.' + version;
}
}
return packId;
}
public static boolean isPackFamilyId(String id) {
return id.split("\\.").length == 2; //$NON-NLS-1$
}
@Override
public Set<String> getAllDeviceNames() {
if (deviceNames == null) {
deviceNames = new HashSet<String>();
if(isDevicelessPack()) {
return deviceNames;
}
collectDeviceNames(getGrandChildren(CmsisConstants.DEVICES_TAG), deviceNames);
collectDeviceNames(getGrandChildren(CmsisConstants.BOARDS_TAG), deviceNames);
}
return deviceNames;
}
protected void collectDeviceNames(Collection<? extends ICpItem> items, Set<String> deviceNames) {
if (items == null || items.isEmpty()) {
return;
}
for (ICpItem item : items) {
if (item instanceof ICpDeviceItem) {
ICpDeviceItem d = (ICpDeviceItem) item;
deviceNames.add(d.getName());
collectDeviceNames(d, deviceNames);
}
}
}
protected void collectDeviceNames(ICpDeviceItem parent, Set<String> deviceNames) {
if (parent == null || parent.getDeviceItems() == null) {
return;
}
for (ICpItem item : parent.getDeviceItems()) {
if (!(item instanceof ICpDeviceItem)) {
continue;
}
ICpDeviceItem d = (ICpDeviceItem) item;
deviceNames.add(d.getName());
collectDeviceNames(d, deviceNames);
}
}
@Override
public Set<String> getBoardNames() {
if( boardNames == null) {
boardNames = new HashSet<String>();
Collection<? extends ICpItem> items = getGrandChildren(CmsisConstants.DEVICES_TAG);
if (items == null || items.isEmpty()) {
return boardNames;
}
for (ICpItem item : items) {
if (!(item instanceof ICpBoard)) {
continue;
}
boardNames.add(item.getName());
}
}
return boardNames;
}
@Override
public boolean isDevicelessPack() {
if(deviceLess < 0) {
// TODO check more
if (getId().contains("ARM") || //$NON-NLS-1$
(getGrandChildren(CmsisConstants.DEVICES_TAG) == null &&
getGrandChildren(CmsisConstants.BOARDS_TAG) == null)) {
deviceLess = 1;
}else {
deviceLess = 0;
}
}
return deviceLess == 1;
}
@Override
public boolean isLatest() {
return (getParent() != null && getParent().getFirstChild() == this);
}
@Override
public boolean isDeprecated() {
if(deprecated < 0 ) {
Collection<? extends ICpItem> releases = getReleases();
if (releases != null) {
ICpItem latestRelease = releases.iterator().next();
deprecated = latestRelease.hasAttribute(CmsisConstants.DEPRECATED) ? 1 : 0;
} else {
deprecated = 0;
}
}
return deprecated == 1;
}
@Override
public Collection<? extends ICpItem> getReleases() {
return getGrandChildren(CmsisConstants.RELEASES_TAG);
}
@Override
public Collection<? extends ICpItem> getRequiredPacks() {
ICpItem requirements = getFirstChild(CmsisConstants.REQUIREMENTS_TAG);
if (requirements == null) {
return null;
}
return requirements.getGrandChildren(CmsisConstants.PACKAGES_TAG);
}
@Override
public boolean isRequiredPacksInstalled() {
Collection<? extends ICpItem> requiredPacks = getRequiredPacks();
if (requiredPacks == null) {
return true;
}
for (ICpItem requiredPack : requiredPacks) {
ICpPackCollection installedPacks = CpPlugIn.getPackManager().getInstalledPacks();
if (installedPacks == null || installedPacks.getPack(requiredPack.attributes()) == null) {
return false;
}
}
return true;
}
/**
* Replace Vendor.Pack.Version with Vendor/Pack/Version
*
* @param fullPackId the pack's id
* @return the relative installation directory. e.g. ARM/CMSIS/4.5.0
*/
public static String getPackRelativeInstallDir(String fullPackId) {
int iv = fullPackId.indexOf('.');
if (iv == -1) {
return fullPackId;
}
String vendor = fullPackId.substring(0, iv);
int ip = fullPackId.indexOf('.', iv + 1);
if (ip == -1) {
return fullPackId;
}
String pack = fullPackId.substring(iv + 1, ip);
String version = fullPackId.substring(ip + 1);
return vendor + File.separator + pack + File.separator + version;
}
/**
* Get the Full Pack ID of this {@link ICpItem}
*
* @param cpItem the cmsis pack item
* @return a String like Vendor.Pack.Version
*/
public static String getFullPackId(ICpItem cpItem) {
return cpItem.getPackFamilyId() + "." + getCpItemVersion(cpItem); //$NON-NLS-1$
}
/**
* Return this {@link ICpItem}'s release date
*
* @param cpItem the cmsis pack item
* @return a string of the date or an empty string
*/
public static String getCpItemDate(ICpItem cpItem) {
if (cpItem == null || cpItem instanceof ICpPackCollection) {
return CmsisConstants.EMPTY_STRING;
}
String date = CmsisConstants.EMPTY_STRING;
if (CmsisConstants.RELEASE_TAG.equals(cpItem.getTag())) {
date = cpItem.getAttribute(CmsisConstants.DATE);
} else {
String version = cpItem.getPack().getVersion();
Collection<? extends ICpItem> releases = cpItem.getPack().getGrandChildren(CmsisConstants.RELEASES_TAG);
if (releases == null) {
return date;
}
for (ICpItem release : releases) {
if (release.getAttribute(CmsisConstants.VERSION).equals(version)) {
date = release.getAttribute(CmsisConstants.DATE);
break;
}
}
}
return date;
}
/**
* Get the items' pack version (either this pack or a specified release)
*
* @param cpItem the cmsis pack item
* @return pack version or an empty string
*/
public static String getCpItemVersion(ICpItem cpItem) {
if (cpItem == null) {
return CmsisConstants.EMPTY_STRING;
}
String installingVersion = CmsisConstants.EMPTY_STRING;
if (cpItem.getTag().equals(CmsisConstants.RELEASE_TAG)) {
installingVersion = cpItem.getAttribute(CmsisConstants.VERSION);
} else {
installingVersion = cpItem.getPack().getVersion();
}
return installingVersion;
}
}