blob: ff58eb4eeae6ebee4410bb69f37f60caeed89efa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 23.04.2012 Aaron Digulla.
* 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:
* Aaron Digulla - initial API and implementation and/or initial documentation
*******************************************************************************/
package m4e.p2
import groovy.util.Node;
import java.io.File;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class ContentXmlParser {
static final Logger log = LoggerFactory.getLogger( ContentXmlParser )
P2Repo repo
ProviderResolver providerResolver
VersionCache versionCache
DependencyCache dependencyCache = new DependencyCache()
void parseXml( File contentXmlFile ) {
providerResolver = new ProviderResolver( repo: repo, dependencyCache: dependencyCache )
versionCache = repo.versionCache
def doc = new XmlParser().parse( contentXmlFile )
parse( doc )
log.debug( "Parsed ${contentXmlFile}" )
log.debug( "dependencyCache has ${dependencyCache.cache.size()} elements" )
}
void parse( Node doc ) {
String type = doc.'@type'
if( type == 'org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository' ) {
throw new CompositeRepoException()
}
if( type != 'org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository' ) {
throw new P2Exception( "Unsupported repository type ${type}" )
}
def units = doc.units
log.info( "Found ${units.unit.size()} items." )
for( Node unit : units.unit ) {
def isCategory = getProperty( unit, 'org.eclipse.equinox.p2.type.category' )
if( 'true' == isCategory ) {
repo.categories << parseCategory( unit )
continue
}
def artifacts = unit.artifacts[0]
parsePluginOrFeature( unit, artifacts )
}
providerResolver.resolveRequirements()
repo.categories.sort()
repo.features.sort()
repo.plugins.sort()
repo.others.sort { "${it.id} ${it.version}" }
}
P2Category parseCategory( Node unit ) {
def id = unit.'@id'
def version = versionCache.version( unit.'@version' )
def name = getProperty( unit, 'org.eclipse.equinox.p2.name' )
def description = getDescription( unit )
def category = new P2Category( id: id, version: version, name: name, description: description )
category.dependencies = parseDependencies( unit )
return category
}
List<P2Dependency> parseDependencies( Node unit ) {
List<P2Dependency> result = []
//println "parseDependencies ${unit.'@id'} ${unit.requires.size()} ${unit.artifacts.size()}"
if( unit.requires ) {
for( Node required : unit.requires[0].required ) {
def type = required.'@namespace'
def id = required.'@name'
def versionRange = versionCache.range( required.'@range' )
if( id.endsWith( '.feature.jar' ) ) {
continue
}
result << dependencyCache.dependency( id, type, versionRange )
}
}
if( unit.artifacts ) {
for( Node artifact: unit.artifacts[0].artifact ) {
def type = artifact.'@classifier'
def id = artifact.'@id'
def versionRange = versionCache.range( artifact.'@version' )
result << dependencyCache.dependency( id, type, versionRange )
}
}
return result
}
String getProperty( Node unit, String name ) {
def properties = unit.properties
if( !properties || properties.size() == 0 ) {
return null
}
properties = properties[0]
return properties.property.find { name == it.'@name' }?.'@value'
}
void parsePluginOrFeature( Node unit, Node artifacts ) {
String id = unit.'@id'
//def updateFeaturePlugin = getProperty( unit, 'org.eclipse.update.feature.plugin' )
if( id.endsWith( '.feature.jar' ) ) {
// Ignore feature JARs
return
}
String classifier = ''
if( artifacts ) {
classifier = artifacts.artifact[0].'@classifier'
}
def isTypeGroup = getProperty( unit, 'org.eclipse.equinox.p2.type.group' )
//println "${unit.'@id'} ${classifier} ${isTypeGroup}"
if( 'org.eclipse.update.feature' == classifier || 'true' == isTypeGroup || 'false' == isTypeGroup ) {
parseFeature( unit )
return
}
def typeFragment = getProperty( unit, 'org.eclipse.equinox.p2.type.fragment' )
if( 'osgi.bundle' == classifier || 'binary' == classifier || 'true' == typeFragment ) {
parsePlugin( unit )
return
}
if( !artifacts ) {
def requires = unit.requires
if( id.startsWith( 'tooling' ) || id.startsWith( 'epp.package.' ) || !requires ) {
repo.units << parseUnit( unit )
return
}
// println "${id} ${requires}"
}
String xml = xmlToString( unit )
repo.others << new P2Other( id: id, version: versionCache.version( unit.'@version' ), message: "Unable to determine type", xml: xml )
}
P2Unit parseUnit( Node unit ) {
String xml = xmlToString( unit )
String id = unit.'@id'
def result = new P2Unit( id: id, version: versionCache.version( unit.'@version' ), xml: xml )
return result
}
String xmlToString( Node node ) {
StringWriter buffer = new StringWriter( 10240 )
def ip = new IndentPrinter( buffer, ' ' )
def printer = new XmlNodePrinter( ip )
printer.print( node )
String xml = buffer.toString()
return xml
}
P2Feature parseFeature( Node unit ) {
def id = unit.'@id'
def version = versionCache.version( unit.'@version' )
def name = getName( unit )
def description = getDescription( unit )
if( name == description ) {
description = null
}
def result = new P2Feature( id: id, version: version, name: name, description: description )
result.dependencies = parseDependencies( unit )
repo.features << result
providerResolver.register( result, unit )
repo.bundlesById.get( id ) << result
return result
}
String getName( Node unit ) {
String name = getProperty( unit, 'org.eclipse.equinox.p2.name' )
if( name && name.startsWith( '%' ) ) {
String key = 'df_LT.' + name.substring( 1 )
name = getProperty( unit, key )
}
if( name ) {
return name
}
return unit.'@id'
}
String getDescription( Node unit ) {
def description = getProperty( unit, 'org.eclipse.equinox.p2.description' )
if( !description ) {
return null
}
if( description.startsWith( '%' ) ) {
String key = 'df_LT.' + description.substring( 1 )
description = getProperty( unit, key )
}
return description
}
P2Plugin parsePlugin( Node unit ) {
def id = unit.'@id'
def version = versionCache.version( unit.'@version' )
def name = getName( unit )
def description = getDescription( unit )
if( name == description ) {
description = null
}
boolean source = false
if( unit.provides ) {
for( Node provided : unit.provides[0].provided ) {
String namespace = provided.'@namespace'
if( 'org.eclipse.equinox.p2.eclipse.type' == namespace ) {
source = 'source' == provided.'@name'
break
}
}
}
def result = new P2Plugin( id: id, version: version, name: name, description: description, source: source )
result.dependencies = parseDependencies( unit )
repo.plugins << result
providerResolver.register( result, unit )
repo.bundlesById.get( id ) << result
return result
}
}